Capturer et assainir les données de requête
Parfois, les erreurs dans votre code client ne sont pas aussi évidentes que lorsque vous obtenez un écran blanc parce qu’aucune partie de votre code JavaScript ne fonctionne. Parfois, le problème avec votre application est que, pour certaines actions que votre utilisateur peut effectuer, vous formez incorrectement une requête vers le serveur. Le code client fonctionne, vous n’obtenez aucune erreur JS dans la console, mais votre back-end n’apprécie pas vraiment ce que vous lui envoyez.
Avec OpenReplay, vous pouvez capturer la communication client-serveur dans le cadre de votre replay de session standard, et la consulter plus tard. Voyons donc comment nous pouvons faire cela et quel type d’avantage nous pouvons en tirer.
Une application d’exemple
Section titled Une application d’exemplePour les besoins de ce tutoriel, j’ai créé une application React simple qui utilise la Bored API. Il s’agit d’une API très simple qui renvoie une suggestion d’activité aléatoire en fonction de certains paramètres. J’ai donc créé l’application « I’m bored App », qui ressemble à ceci :

Et vous pouvez la trouver en ligne sur Netlify ici, ou si vous souhaitez consulter le code pour l’examiner en détail, il est entièrement disponible sur GitHub.
Cette application est composée de 2 composants, le composant SearchForm, qui s’occupe d’afficher ces 2 champs et le bouton, ainsi que d’envoyer la requête réelle à l’API.
Et le composant Suggestion se contente d’afficher la suggestion dans une jolie boîte.
Je vais me concentrer sur le premier, car c’est le seul qui envoie des requêtes en utilisant la fonction fetch.
Notez que cette technique fonctionne également pour toute requête effectuée avec Axios.
Jetons un coup d’œil rapide au composant pour comprendre ce qu’il fait.
Le code du composant SearchForm
Section titled Le code du composant SearchFormCe n’est pas un composant complexe, mais il y a une section particulièrement pertinente pour ce cas d’usage précis, alors jetons-y un coup d’œil rapide.
import { Container, Col, Form, Row, Button } from 'react-bootstrap';
const SearchForm = ({setResult, fetcher}) => {
const getSomething = async (evt) => {
evt.preventDefault()
let form = evt.target
const API_URL = "/api/activity?"
let getParams = {}
if(form.participants.value !== '') {
getParams.participants = form.participants.value
}
if(form.priceRange.value !== '') {
let prices = form.priceRange.value.split("_")
getParams.minprice = prices[0]
getParams.maxprice = prices[1]
}
let results = await fetcher(API_URL + new URLSearchParams(getParams), {
mode: 'no-cors'
})
setResult(await results.json())
return false
}
return (
<Container>
<Form onSubmit={getSomething}>
<Row>
<Col>
<Form.Group controlId='participants' >
<Form.Label>Participants</Form.Label>
<Form.Control type='text' name="totalParticipants" placeholder='Leave empty if you dont care...'></Form.Control>
</Form.Group>
</Col>
<Col>
<Form.Group controlId='priceRangeId'>
<Form.Label>Price range</Form.Label>
<Form.Select name="priceRange" >
<option value="" >Select one or leave empty if you dont care</option>
<option value="0.0">Free</option>
<option value="0.1_0.5">Cheap</option>
<option value="0.6_1.0">Expensive</option>
</Form.Select>
</Form.Group>
</Col>
</Row>
<Row className='m-3'>
<Col>
<Form.Group>
<Button variant="primary" type="submit">Get me something!</Button>
</Form.Group>
</Col>
</Row>
</Form>
</Container>
)
}
export default SearchForm
Remarquez la fonction getSomething, c’est là que la plus grande partie de la magie opère. La fonction est appelée lorsque l’événement submit du formulaire est déclenché.
Lorsque cela se produit, la fonction récupère l’événement synthétique avec le formulaire lié à l’intérieur de la propriété target. Nous capturons simplement les valeurs de chacun des filtres (le champ de saisie et la liste déroulante), puis nous exécutons la requête avec la fonction fetch.
Remarquez que l’URL ne cible pas directement l’endpoint de la BoredAPI. C’est parce que, pour que la requête fonctionne et ne soit pas bloquée à cause des restrictions CORS, j’ai configuré un proxy sur le backend pour rediriger toutes les requêtes de /api vers l’API réelle.
Maintenant que vous avez vu le code, jetons un coup d’œil à ce que vous obtiendriez si vous installiez le tracker d’OpenReplay sans le plugin fetch.
Capture de données standard avec OpenReplay
Section titled Capture de données standard avec OpenReplayPour cet exemple, je vais utiliser la version NPM du package ; si vous ne savez pas comment faire, consultez la documentation puis revenez ici.

Voici l’interface du replay de session par défaut. Remarquez que dans la moitié inférieure j’ai déjà sélectionné l’onglet « Network », mais bien qu’il affiche les requêtes effectuées, il n’y a aucun détail à leur sujet. Même si vous cliquez sur l’une d’elles, vous n’obtiendrez que le minimum de détails disponibles :

Alors, que pouvons-nous faire ? Vous pouvez activer la capture des informations de requête avec l’objet Network options. Examinons cela.
Capturer les données de requête dans vos replays de session
Section titled Capturer les données de requête dans vos replays de sessionPour cela, tout ce que nous avons à faire est d’ajouter une option de configuration lorsque vous instanciez le tracker.
Désormais, lorsque vous écrirez la ligne new tracker(...), vous ajouterez une nouvelle propriété :
import Tracker from '@openreplay/tracker';
const tracker = new Tracker({
projectKey: "<your project key>",
network: {
capturePayload: true //start capturing the payload of every request
}
});
C’est tout ce que nous avons à faire ; à partir de maintenant, chaque fois que vous effectuez une requête, les données seront enregistrées par le tracker. Déployez maintenant la modification, testez l’application, fermez l’onglet et attendez quelques minutes. La session devrait apparaître assez vite et vous pourrez appuyer sur le bouton « play ».
Inspecter la communication client-serveur
Section titled Inspecter la communication client-serveurPour les besoins de l’exemple, examinons également un problème que j’ai commencé à observer après avoir publié l’application.
Remarquez l’encadré d’avertissement que j’obtiens dans ce cas :

En tant que développeur qui a codé ceci, je sais quoi faire pour le tester et comprendre où se trouve le bug. Cependant, en tant qu’utilisateur, l’erreur ne me dit pas grand-chose, et je pourrais ne pas être en mesure de la communiquer d’une manière que l’équipe de développement puisse comprendre. Alors, à la place, en tant qu’utilisateur, je peux simplement me plaindre auprès de l’entreprise que leur application ne fonctionne pas, et vous, en tant que développeur responsable de l’application, pouvez jeter un coup d’œil à ma session et inspecter la requête envoyée par le client ainsi que la réponse du serveur.

Regardez maintenant l’interface du replay de session. Dans l’onglet Network, vous pouvez voir les requêtes que nous avons effectuées vers l’API externe.
Tout ce que nous avons à faire maintenant, c’est de trouver le moment où nous obtenons la réponse d’erreur et de regarder les requêtes effectuées. Il y a de fortes chances que vous voyiez le problème dans les détails de la requête. Dans notre cas, l’erreur indique « Failed to query due to error in arguments », ce qui signifie que lorsque nous sélectionnons l’option « Free » dans la liste déroulante, nous n’envoyons pas une requête valide. Jetons donc un coup d’œil à ses détails.

Voyez-vous le problème ? Laissez-moi vous aider :

Oui, j’envoie un undefined comme valeur de l’attribut maxprice. J’ai complètement raté cela dans ma logique, et je l’ai repéré en inspectant la requête.
Certes, c’est une correction facile maintenant que je sais où se trouve le problème, mais grâce à ce processus, j’aurais pu soit rédiger un rapport d’erreur très détaillé, soit aider directement le développeur à identifier et résoudre le problème sans avoir à le tester moi-même et à reproduire l’incident.
Mettre la confidentialité à l’épreuve
Section titled Mettre la confidentialité à l’épreuveTrès bien, poussons cet exemple un peu plus loin ; imaginons que j’ai également besoin du numéro de téléphone de mon utilisateur pour cette requête. Clairement, je n’en ai pas besoin, mais jouez le jeu une minute.
Je vais ajouter le champ au formulaire, et je vais mettre à jour le code pour capturer cette valeur et l’envoyer dans le cadre de la requête.
Le HTML du formulaire consiste simplement à ajouter un nouvel élément Col comme ceci :
<!-- previous code -->
<Col>
<Form.Group controlId='phoneNumber'>
<Form.Label>Phone Number</Form.Label>
<Form.Control type='number' name="phoneNumber" placeholder='Enter your phone number here please'></Form.Control>
</Form.Group>
</Col>
<!-- rest of the code -->
Et ajouter le contenu de ce champ à la requête réelle ne nécessite qu’une seule ligne de code :
getParams.phonenumber = form.phoneNumber.value
Maintenant, que se passe-t-il si nous utilisons ce nouveau code et capturons une session avec OpenReplay ? Eh bien, deux choses :
- Le replay réel que vous regardez assainira automatiquement le contenu du champ du numéro de téléphone et il ne sera affiché à personne qui le visionne.
- Les informations de requête capturées par le plugin afficheront en revanche la valeur.
La capture d’écran suivante montre ce que je viens de décrire :

Dans la partie droite de l’écran, vous pouvez voir le numéro de téléphone complet. Cela se produit parce que, si le tracker normal peut comprendre que le champ du numéro de téléphone est un champ numérique, il ne capturera pas sa saisie au cas où le numéro représenterait des informations personnelles. Mais du côté de la requête, nous ne pouvons pas vraiment faire cette supposition, car le développeur aurait pu faire n’importe quoi avec les données, ou même avec le nom du paramètre. La question est donc : pouvons-nous protéger la confidentialité de notre utilisateur avec ce plugin ?
Et la réponse, je suis heureux de l’annoncer, est : OUI, nous le pouvons.
Assainir les données de requête
Section titled Assainir les données de requêteSi vous revenez au début de ce tutoriel, lorsque j’ai configuré les options de network, vous verrez que je n’ai rien dit au sujet de l’assainissement. Cependant, dans le cadre de ces options, vous pouvez spécifier un callback destiné à assainir les données. Ce callback reçoit un seul attribut contenant à la fois l’objet de requête et l’objet de réponse. Vous pouvez alors choisir de les modifier comme bon vous semble ; ils n’affecteront pas la requête réelle mais changeront la manière dont les données sont affichées dans l’interface d’OpenReplay.
Par exemple, disons que je veux modifier l’attribut « phonenumber » et supprimer les chiffres afin d’éviter de divulguer cette information. Cela peut se faire ainsi :
const tracker = new Tracker({
projectKey: "<your project id>",
network: {
capturePayload: true,
sanitizer: (data) => { //we change the content of the "phonenumber" parameter from the url
data.url = data.url.replace(/phonenumber=([0-9]+)/, "phonenumber=XXXXXX")
return data
}
}
});
Comme vous pouvez le voir, le changement est simple, nous remplaçons uniquement les chiffres de cet attribut, de sorte que la requête ressemble maintenant à ceci dans notre interface :

Désormais, les données de votre utilisateur sont à nouveau protégées.
Des questions ?
Section titled Des questions ?Si vous souhaitez consulter le code pour examiner cet exemple en détail, vous pouvez le trouver ici sur GitHub. Si vous rencontrez des problèmes pour configurer le plugin Fetch ou le Tracker lui-même, contactez-nous sur notre communauté Slack et posez directement vos questions à nos développeurs !