Guide d'utilisation de la fonction de script d'APICatcher
APICatcher dispose d'un moteur de script basé sur JavaScript intégré, vous permettant d'écrire des scripts personnalisés pour intercepter et modifier les requêtes et les réponses HTTP/HTTPS. La fonction de script est puissante et flexible, adaptée au débogage de développement, aux tests d'API, à la simulation de données et à d'autres scénarios.
Table des matières
- Démarrage rapide
- Structure de base du script
- Fonction d'interception de requête interceptRequest
- Fonction d'interception de réponse interceptResponse
- API intégrée
- Exemples pratiques
- Remarques
Démarrage rapide
- Ouvrez APICatcher et accédez à la page de gestion des "Scripts".
- Cliquez sur "Ajouter un script", le système remplira automatiquement le code de modèle.
- Définissez les conditions de correspondance du script (telles que Host, Path, etc.) pour déterminer quelles requêtes le script affecte.
- Écrivez votre logique d'interception.
- Après avoir activé le script, commencez la capture de paquets pour qu'elle prenne effet.
Structure de base du script
Chaque script peut contenir deux fonctions :
// Interception de requête (Facultatif)
function interceptRequest(request) {
// Votre logique
return { action: 'passthrough' };
}
// Interception de réponse (Facultatif)
function interceptResponse(request, response) {
// Votre logique
return { action: 'passthrough' };
}
- Vous pouvez en définir un seul ou les deux.
- Les scripts sont exécutés par ordre de priorité et d'heure de création.
- Une fois qu'un script renvoie un résultat autre que
passthrough, les scripts suivants ne seront pas exécutés.
Fonction d'interception de requête interceptRequest
Lorsqu'une requête HTTP correspondante arrive, la fonction interceptRequest est appelée.
Paramètres : objet request
| Propriété | Type | Description |
|---|---|---|
method | string | Méthode HTTP (GET, POST, PUT, DELETE, etc.) |
url | string | URL complète |
host | string | Nom d'hôte |
port | number | Numéro de port |
path | string | Chemin de la requête |
scheme | string | Protocole (http / https) |
headers | object | En-têtes de requête (objet clé-valeur) |
body | string | Chaîne du corps de la requête |
queryParams | object | Paramètres de requête d'URL (objet clé-valeur) |
Valeur de retour
Renvoie un objet contenant un champ action pour déterminer comment traiter la requête :
1. Laisser passer la requête (passthrough)
return { action: 'passthrough' };
N'apporte aucune modification, la requête est envoyée normalement.
2. Modifier la requête (modify)
request.headers['Authorization'] = 'Bearer my-token';
request.body = JSON.stringify({ modified: true });
return { action: 'modify', request: request };
Poursuivre l'envoi après avoir modifié le contenu de la requête.
3. Simuler la réponse (mock)
return {
action: 'mock',
response: {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ success: true, data: 'mocked' })
}
};
N'envoie pas de véritable requête, renvoie directement la réponse simulée.
4. Rediriger (redirect)
return {
action: 'redirect',
url: 'https://new-api.example.com' + request.path,
statusCode: 302 // Facultatif, 302 par défaut
};
Redirige la requête vers une autre URL.
5. Ignorer la requête (drop)
return { action: 'drop' };
Ignore directement la requête, sans l'envoyer ni y répondre.
Fonction d'interception de réponse interceptResponse
Une fois que le serveur renvoie une réponse, la fonction interceptResponse est appelée.
Paramètres
- request : Informations sur la requête d'origine (comme ci-dessus)
- response : Informations sur la réponse
| Propriété | Type | Description |
|---|---|---|
statusCode | number | Code d'état HTTP |
headers | object | En-têtes de réponse (objet clé-valeur) |
body | string | Chaîne du corps de la réponse |
Valeur de retour
1. Laisser passer la réponse (passthrough)
return { action: 'passthrough' };
2. Modifier la réponse (modify)
var data = JSON.parse(response.body);
data.injected = true;
response.body = JSON.stringify(data);
return { action: 'modify', response: response };
3. Retarder la réponse (delay)
return {
action: 'delay',
response: response,
delay: 3000 // Retard de 3000 millisecondes
};
4. Ignorer la réponse (drop)
return { action: 'drop' };
API intégrée
Les objets globaux suivants sont prédéfinis dans l'environnement de script et peuvent être utilisés directement dans interceptRequest et interceptResponse.
httpClient — Requêtes HTTP
Lancer des requêtes HTTP/HTTPS dans le script. L'appel est synchrone, le script attendra que la requête soit terminée avant de poursuivre l'exécution. Le temps passé sur chaque requête sera automatiquement enregistré dans le journal pour faciliter le dépannage des problèmes de performances.
Méthodes
// Requête GET
httpClient.get(url)
httpClient.get(url, headers)
// Requête POST
httpClient.post(url)
httpClient.post(url, body)
httpClient.post(url, body, headers)
// Requête PUT
httpClient.put(url)
httpClient.put(url, body)
httpClient.put(url, body, headers)
// Requête DELETE
httpClient.delete(url)
httpClient.delete(url, headers)
Description des paramètres
| Paramètre | Type | Requis | Description |
|---|---|---|---|
url | string | ✅ | URL de requête complète (http:// ou https://) |
body | string | ❌ | Chaîne du corps de la requête (pour JSON, utilisez JSON.stringify()) |
headers | object | ❌ | Objet d'en-tête de requête |
Valeur de retour
Toutes les méthodes renvoient un objet de réponse de même structure :
{
statusCode: 200, // Code d'état HTTP (-1 si la requête échoue)
headers: { ... }, // Objet d'en-tête de réponse
body: "...", // Chaîne du corps de la réponse
error: "" // Message d'erreur (chaîne vide en cas de succès)
}
Exemple
// Requête GET simple
var resp = httpClient.get('https://api.example.com/status');
console.log('Status: ' + resp.statusCode);
// Requête GET avec des en-têtes
var resp = httpClient.get('https://api.example.com/user', {
'Authorization': 'Bearer my-token'
});
// POSTer des données JSON
var resp = httpClient.post(
'https://api.example.com/data',
JSON.stringify({ name: 'test', value: 123 }),
{ 'Content-Type': 'application/json' }
);
// Vérifier si la requête a réussi
if (resp.error) {
console.error('La requête a échoué : ' + resp.error);
} else {
var data = JSON.parse(resp.body);
console.log('Données de réponse : ' + JSON.stringify(data));
}
Journalisation automatique du temps consommé
Chaque fois qu'un appel httpClient est terminé, le moteur affiche automatiquement un journal :
[Script] httpClient.get https://api.example.com/status -> 200 (156ms)
[Script] httpClient.post https://api.example.com/data -> 201 (342ms)
Vous pouvez afficher ces informations dans le panneau des journaux d'APICatcher pour vous aider à localiser les requêtes lentes.
⚠️ Attention : Les appels à httpClient sont synchrones et bloqueront l'exécution du script jusqu'à ce que la requête HTTP soit terminée (délai d'attente de 15 secondes). Si vous lancez une requête HTTP qui prend beaucoup de temps dans le script, cela peut retarder la réponse de la requête interceptée d'origine. Veuillez prêter attention aux données de temps consommé dans les journaux.
localStore — Stockage local
Fournit un simple stockage persistant local clé-valeur (Key-Value). Les données sont stockées dans les UserDefaults de l'application, et tous les scripts partagent le même espace de stockage. Si vous devez isoler les données par Host ou d'autres dimensions, veuillez ajouter vous-même un préfixe à la clé (par exemple, request.host + '_token').
Méthodes
// Écrire des données
localStore.write(key, value)
// Lire des données
localStore.read(key) // Renvoie une chaîne ou null
// Supprimer des données
localStore.remove(key)
Description des paramètres
| Paramètre | Type | Description |
|---|---|---|
key | string | Nom de la clé à stocker |
value | any | Valeur à stocker (sera automatiquement convertie en chaîne) |
Description du stockage
- Tous les scripts partagent le même espace de stockage
- Les données sont conservées dans le bac à sable de l'application (stockage local) et existeront toujours après le redémarrage de l'application
- Si vous avez besoin d'isoler par Host, veuillez inclure les informations Host dans la clé, par exemple :
// Isolation manuelle par host
var key = request.host + '_token';
localStore.write(key, 'my-token');
Exemple
// Lecture et écriture de base
localStore.write('counter', '1');
var count = localStore.read('counter'); // '1'
console.log('Count: ' + count);
// Stocker un objet JSON
var config = { debug: true, maxRetry: 3 };
localStore.write('config', JSON.stringify(config));
// Lire un objet JSON
var raw = localStore.read('config');
if (raw) {
var config = JSON.parse(raw);
console.log('Debug mode: ' + config.debug);
}
// Supprimer des données
localStore.remove('counter');
var v = localStore.read('counter'); // null
console — Sortie de journal
Utilisé pour générer des journaux dans le script, qui peuvent être consultés dans le panneau des journaux d'API Catcher.
console.log('Journal normal'); // Niveau d'information
console.warn('Journal d\'avertissement'); // Niveau d'avertissement
console.error('Journal d\'erreur'); // Niveau d'erreur
Prend en charge plusieurs paramètres et les objets seront automatiquement sérialisés en JSON :
console.log('Informations de requête :', request.method, request.url);
console.log('Données de réponse :', { status: response.statusCode, body: response.body });
Exemples pratiques
Exemple 1 : Injection automatique de jeton d'authentification
Interceptez toutes les requêtes vers api.myserver.com et ajoutez automatiquement l'en-tête Authorization. Le Token est obtenu à partir de l'API de connexion et mis en cache dans localStore.
function interceptRequest(request) {
// Ne traiter que le serveur cible
if (!request.host.includes('api.myserver.com')) {
return { action: 'passthrough' };
}
// Essayer de lire le jeton depuis le cache
var token = localStore.read('auth_token');
var tokenExpiry = localStore.read('auth_token_expiry');
// Vérifier si le jeton a expiré (en utilisant l'horodatage, en secondes)
var now = Math.floor(Date.now() / 1000);
if (!token || !tokenExpiry || now > parseInt(tokenExpiry)) {
// Le jeton n'existe pas ou a expiré, reconnectez-vous pour l'obtenir
console.log('Token expired, re-authenticating...');
var loginResp = httpClient.post(
'https://api.myserver.com/auth/login',
JSON.stringify({ username: 'testuser', password: 'testpass' }),
{ 'Content-Type': 'application/json' }
);
if (loginResp.statusCode === 200) {
var loginData = JSON.parse(loginResp.body);
token = loginData.token;
// Mettre en cache le jeton, le définir pour qu'il expire dans 1 heure
localStore.write('auth_token', token);
localStore.write('auth_token_expiry', String(now + 3600));
console.log('New token cached successfully');
} else {
console.error('Login failed: ' + loginResp.statusCode);
return { action: 'passthrough' };
}
}
// Injecter l'en-tête Authorization
request.headers['Authorization'] = 'Bearer ' + token;
return { action: 'modify', request: request };
}
Exemple 2 : Transfert de données d'API/Rapports de journaux
Rapportez les informations de requête et de réponse interceptées à votre serveur d'analyse de journaux.
function interceptResponse(request, response) {
// Signaler uniquement les API de chemins spécifiques
if (!request.path.startsWith('/api/v2/')) {
return { action: 'passthrough' };
}
// Collecter les informations de requête et de réponse
var logData = {
timestamp: new Date().toISOString(),
request: {
method: request.method,
url: request.url,
headers: request.headers
},
response: {
statusCode: response.statusCode,
body: response.body
}
};
// Signaler au serveur de journaux (remarque : la requête est synchrone et bloquera le retour de la réponse actuelle)
var reportResp = httpClient.post(
'https://log.myserver.com/api/collect',
JSON.stringify(logData),
{ 'Content-Type': 'application/json' }
);
if (reportResp.error) {
console.warn('Log report failed: ' + reportResp.error);
}
// Laisser passer la réponse d'origine
return { action: 'passthrough' };
}
Exemple 3 : Tests A/B — Modifier les réponses dynamiquement
Utilisez un compteur pour implémenter une simple répartition A/B, en renvoyant alternativement différentes données simulées.
function interceptRequest(request) {
if (request.path !== '/api/recommend') {
return { action: 'passthrough' };
}
// Lire le compteur alternatif à partir de localStore
var count = parseInt(localStore.read('ab_counter') || '0');
count++;
localStore.write('ab_counter', String(count));
// Renvoyer alternativement différentes versions pour les nombres pairs et impairs
var version = (count % 2 === 0) ? 'A' : 'B';
if (version === 'A') {
return {
action: 'mock',
response: {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
version: 'A',
items: [{ id: 1, name: 'Plan de recommandation A-1' }, { id: 2, name: 'Plan de recommandation A-2' }]
})
}
};
} else {
return {
action: 'mock',
response: {
statusCode: 200,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
version: 'B',
items: [{ id: 3, name: 'Plan de recommandation B-1' }, { id: 4, name: 'Plan de recommandation B-2' }]
})
}
};
}
}
Exemple 4 : Protection de limite de débit de requêtes
Enregistrez la fréquence de requête de la même API et renvoyez l'erreur 429 lorsqu'elle dépasse le seuil.
function interceptRequest(request) {
if (!request.path.startsWith('/api/')) {
return { action: 'passthrough' };
}
var key = 'rate_' + request.path;
var now = Math.floor(Date.now() / 1000);
// Lire l'heure et le nombre de la dernière requête
var rawData = localStore.read(key);
var data = rawData ? JSON.parse(rawData) : { count: 0, windowStart: now };
// Si la fenêtre de temps dépasse 60 secondes, réinitialiser le compteur
if (now - data.windowStart > 60) {
data = { count: 0, windowStart: now };
}
data.count++;
localStore.write(key, JSON.stringify(data));
// Maximum de 10 fois par minute
if (data.count > 10) {
console.warn('Rate limit exceeded for ' + request.path);
return {
action: 'mock',
response: {
statusCode: 429,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
error: 'Too Many Requests',
retryAfter: 60 - (now - data.windowStart)
})
}
};
}
return { action: 'passthrough' };
}
Remarques
-
httpClient est un appel synchrone : Les requêtes HTTP lancées dans le script bloqueront l'exécution du script jusqu'à ce que la requête soit terminée ou expire (15 secondes). Cela affectera la vitesse de traitement de la requête d'origine. Veuillez faire attention aux informations sur le temps de consommation de la requête qui sont automatiquement générées dans les journaux.
-
Stockage partagé localStore : Tous les scripts partagent le même espace de stockage. Si vous avez besoin d'isoler des données par Host, veuillez ajouter vous-même un préfixe à la clé.
-
Ordre d'exécution du script : Plusieurs scripts sont triés et exécutés par priorité. Une fois qu'un script renvoie un résultat différent de
passthrough, les scripts suivants seront ignorés. -
Scripts distants : Prend en charge le chargement de scripts à partir d'URL. Le contenu du script distant sera automatiquement extrait lors du démarrage de la capture de paquets. Si l'extraction échoue, le script sera ignoré.
-
Traitement JSON : Le corps des requêtes/réponses est composé de chaînes. Lorsque vous devez traiter des données JSON, utilisez
JSON.parse()pour les analyser etJSON.stringify()pour les sérialiser. -
Gestion des erreurs : Il est recommandé d'utiliser
try-catchdans la logique clé et d'enregistrer les exceptions viaconsole.error()pour éviter que la chaîne d'interception ne soit interrompue en raison d'un plantage du script. -
Fonctions auxiliaires : Le moteur possède deux fonctions utilitaires intégrées :
safeJsonParse(str)— Analyse JSON sécurisée, renvoie null en cas d'échecdeepClone(obj)— Copie approfondie de l'objet