APICatcher Skript-Funktion Benutzerhandbuch

APICatcher verfügt über eine integrierte JavaScript-basierte Skript-Engine, mit der Sie benutzerdefinierte Skripte schreiben können, um HTTP/HTTPS-Anforderungen und -Antworten abzufangen und zu ändern. Die Skriptfunktion ist leistungsstark und flexibel und eignet sich für das Entwicklungs-Debugging, API-Tests, Datensimulation und andere Szenarien.


Inhaltsverzeichnis


Schnellstart

  1. Öffnen Sie APICatcher und rufen Sie die Verwaltungsseite "Skripte" auf.
  2. Klicken Sie auf "Skript hinzufügen". Das System füllt den Vorlagencode automatisch aus.
  3. Legen Sie die Übereinstimmungsbedingungen des Skripts (z. B. Host, Path usw.) fest, um zu bestimmen, für welche Anforderungen das Skript wirksam ist.
  4. Schreiben Sie Ihre Abfanglogik.
  5. Nach dem Aktivieren des Skripts beginnen Sie mit der Paketerfassung, damit es wirksam wird.

Grundlegende Struktur des Skripts

Jedes Skript kann zwei Funktionen enthalten:

// Anforderungsabfangen (Optional)
function interceptRequest(request) {
    // Ihre Logik
    return { action: 'passthrough' };
}

// Antwortabfangen (Optional)
function interceptResponse(request, response) {
    // Ihre Logik
    return { action: 'passthrough' };
}
  • Sie können nur eine davon oder beide definieren.
  • Die Skripte werden in der Reihenfolge ihrer Priorität und Erstellungszeit ausgeführt.
  • Sobald ein Skript ein anderes Ergebnis als passthrough zurückgibt, werden nachfolgende Skripte nicht mehr ausgeführt.

Anforderungsabfangfunktion interceptRequest

Wenn eine übereinstimmende HTTP-Anforderung eintrifft, wird die Funktion interceptRequest aufgerufen.

Parameter: request-Objekt

EigenschaftTypBeschreibung
methodstringHTTP-Methode (GET, POST, PUT, DELETE usw.)
urlstringVollständige URL
hoststringHostname
portnumberPortnummer
pathstringAnforderungspfad
schemestringProtokoll (http / https)
headersobjectAnforderungsheader (Key-Value-Objekt)
bodystringAnforderungstext-Zeichenfolge
queryParamsobjectURL-Abfrageparameter (Key-Value-Objekt)

Rückgabewert

Gibt ein Objekt zurück, das ein action-Feld enthält, um zu bestimmen, wie die Anforderung verarbeitet werden soll:

1. Anforderung durchlassen (passthrough)

return { action: 'passthrough' };

Nimmt keine Änderungen vor, die Anforderung wird normal gesendet.

2. Anforderung ändern (modify)

request.headers['Authorization'] = 'Bearer my-token';
request.body = JSON.stringify({ modified: true });
return { action: 'modify', request: request };

Fährt mit dem Senden nach Änderung des Anforderungsinhalts fort.

3. Antwort simulieren (mock)

return {
    action: 'mock',
    response: {
        statusCode: 200,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ success: true, data: 'mocked' })
    }
};

Sendet keine echte Anforderung, sondern gibt die simulierte Antwort direkt zurück.

4. Umleiten (redirect)

return {
    action: 'redirect',
    url: 'https://new-api.example.com' + request.path,
    statusCode: 302  // Optional, standardmäßig 302
};

Leitet die Anforderung an eine andere URL um.

5. Anforderung verwerfen (drop)

return { action: 'drop' };

Verwirft die Anforderung direkt, ohne sie zu senden oder zu antworten.


Antwortabfangfunktion interceptResponse

Nachdem der Server eine Antwort zurückgegeben hat, wird die Funktion interceptResponse aufgerufen.

Parameter

  • request: Informationen zur ursprünglichen Anforderung (wie oben)
  • response: Antwortinformationen
EigenschaftTypBeschreibung
statusCodenumberHTTP-Statuscode
headersobjectAntwortheader (Key-Value-Objekt)
bodystringAntworttext-Zeichenfolge

Rückgabewert

1. Antwort durchlassen (passthrough)

return { action: 'passthrough' };

2. Antwort ändern (modify)

var data = JSON.parse(response.body);
data.injected = true;
response.body = JSON.stringify(data);
return { action: 'modify', response: response };

3. Antwort verzögern (delay)

return {
    action: 'delay',
    response: response,
    delay: 3000  // 3000 Millisekunden verzögern
};

4. Antwort verwerfen (drop)

return { action: 'drop' };

Eingebaute API

Die folgenden globalen Objekte sind in der Skriptumgebung voreingestellt und können direkt in interceptRequest und interceptResponse verwendet werden.

httpClient — HTTP-Anforderungen

Starten Sie HTTP/HTTPS-Anforderungen innerhalb des Skripts. Der Aufruf ist synchron, das Skript wartet, bis die Anforderung abgeschlossen ist, bevor die Ausführung fortgesetzt wird. Die für jede Anforderung aufgewendete Zeit wird automatisch im Protokoll aufgezeichnet, um die Fehlerbehebung bei Leistungsproblemen zu erleichtern.

Methoden

// GET-Anforderung
httpClient.get(url)
httpClient.get(url, headers)

// POST-Anforderung
httpClient.post(url)
httpClient.post(url, body)
httpClient.post(url, body, headers)

// PUT-Anforderung
httpClient.put(url)
httpClient.put(url, body)
httpClient.put(url, body, headers)

// DELETE-Anforderung
httpClient.delete(url)
httpClient.delete(url, headers)

Parameterbeschreibung

ParameterTypErforderlichBeschreibung
urlstringVollständige Anforderungs-URL (http:// oder https://)
bodystringAnforderungstext-Zeichenfolge (für JSON verwenden Sie JSON.stringify())
headersobjectAnforderungsheader-Objekt

Rückgabewert

Alle Methoden geben ein Antwortobjekt mit derselben Struktur zurück:

{
    statusCode: 200,        // HTTP-Statuscode (-1, wenn die Anforderung fehlschlägt)
    headers: { ... },       // Antwortheader-Objekt
    body: "...",            // Antworttext-Zeichenfolge
    error: ""              // Fehlermeldung (leere Zeichenfolge bei Erfolg)
}

Beispiel

// Einfache GET-Anforderung
var resp = httpClient.get('https://api.example.com/status');
console.log('Status: ' + resp.statusCode);

// GET-Anforderung mit Headern
var resp = httpClient.get('https://api.example.com/user', {
    'Authorization': 'Bearer my-token'
});

// JSON-Daten mit POST senden
var resp = httpClient.post(
    'https://api.example.com/data',
    JSON.stringify({ name: 'test', value: 123 }),
    { 'Content-Type': 'application/json' }
);

// Überprüfen, ob die Anforderung erfolgreich war
if (resp.error) {
    console.error('Anforderung fehlgeschlagen: ' + resp.error);
} else {
    var data = JSON.parse(resp.body);
    console.log('Antwortdaten: ' + JSON.stringify(data));
}

Automatische Protokollierung des Zeitaufwands

Jedes Mal, wenn ein httpClient-Aufruf abgeschlossen ist, gibt die Engine automatisch ein Protokoll aus:

[Script] httpClient.get https://api.example.com/status -> 200 (156ms)
[Script] httpClient.post https://api.example.com/data -> 201 (342ms)

Sie können diese Informationen im Protokollfenster von APICatcher anzeigen, um langsame Anforderungen zu lokalisieren.

⚠️ Hinweis: Aufrufe an httpClient sind synchron und blockieren die Ausführung des Skripts, bis die HTTP-Anforderung abgeschlossen ist (Zeitlimit 15 Sekunden). Wenn Sie im Skript eine zeitaufwändige HTTP-Anforderung starten, kann dies zu einer Verzögerung bei der Antwort auf die ursprünglich abgefangene Anforderung führen. Bitte beachten Sie die im Protokoll angegebenen Zeitangaben.


localStore — Lokaler Speicher

Bietet einfachen lokalen, persistenten Schlüssel-Wert-Speicher (Key-Value). Die Daten werden in den UserDefaults der App gespeichert, und alle Skripte teilen sich denselben Speicherplatz. Wenn Sie Daten nach Host oder anderen Dimensionen isolieren müssen, fügen Sie dem Schlüssel selbst ein Präfix hinzu (z. B. request.host + '_token').

Methoden

// Daten schreiben
localStore.write(key, value)

// Daten lesen
localStore.read(key)     // Gibt string oder null zurück

// Daten löschen
localStore.remove(key)

Parameterbeschreibung

ParameterTypBeschreibung
keystringDer Name des zu speichernden Schlüssels
valueanyDer zu speichernde Wert (wird automatisch in eine Zeichenfolge konvertiert)

Speicherbeschreibung

  • Alle Skripte teilen sich denselben Speicherplatz
  • Die Daten werden in der Sandbox der App (lokaler Speicher) aufbewahrt und sind auch nach einem Neustart der App noch vorhanden
  • Wenn Sie nach Host isolieren müssen, fügen Sie die Host-Informationen in den Schlüssel ein, z. B.:
// Manuelle Isolation nach Host
var key = request.host + '_token';
localStore.write(key, 'my-token');

Beispiel

// Grundlegendes Lesen und Schreiben
localStore.write('counter', '1');
var count = localStore.read('counter');   // '1'
console.log('Count: ' + count);

// JSON-Objekt speichern
var config = { debug: true, maxRetry: 3 };
localStore.write('config', JSON.stringify(config));

// JSON-Objekt lesen
var raw = localStore.read('config');
if (raw) {
    var config = JSON.parse(raw);
    console.log('Debug mode: ' + config.debug);
}

// Daten löschen
localStore.remove('counter');
var v = localStore.read('counter');  // null

console — Protokollausgabe

Wird verwendet, um Protokolle innerhalb des Skripts auszugeben, die im Protokollfenster von API Catcher angezeigt werden können.

console.log('Normales Protokoll');          // Informationsebene
console.warn('Warnprotokoll'); // Warnstufe
console.error('Fehlerprotokoll');      // Fehlerebene

Unterstützt mehrere Parameter, und Objekte werden automatisch in JSON serialisiert:

console.log('Anforderungsinformationen:', request.method, request.url);
console.log('Antwortdaten:', { status: response.statusCode, body: response.body });

Praktische Beispiele

Beispiel 1: Automatische Injektion des Authentifizierungstokens

Fangen Sie alle Anforderungen an api.myserver.com ab und fügen Sie automatisch den Authorization-Header hinzu. Das Token wird von der Login-API bezogen und im localStore zwischengespeichert.

function interceptRequest(request) {
    // Nur den Zielserver verarbeiten
    if (!request.host.includes('api.myserver.com')) {
        return { action: 'passthrough' };
    }
    
    // Versuchen, das Token aus dem Cache zu lesen
    var token = localStore.read('auth_token');
    var tokenExpiry = localStore.read('auth_token_expiry');
    
    // Überprüfen, ob das Token abgelaufen ist (unter Verwendung des Zeitstempels in Sekunden)
    var now = Math.floor(Date.now() / 1000);
    if (!token || !tokenExpiry || now > parseInt(tokenExpiry)) {
        // Das Token ist nicht vorhanden oder abgelaufen, melden Sie sich erneut an, um es zu erhalten
        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;
            // Token zwischenspeichern, so einstellen, dass es nach 1 Stunde abläuft
            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' };
        }
    }
    
    // Authorization-Header injizieren
    request.headers['Authorization'] = 'Bearer ' + token;
    return { action: 'modify', request: request };
}

Beispiel 2: Weiterleitung von API-Daten/Protokollierung

Melden Sie die abgefangenen Anforderungs- und Antwortinformationen an Ihren Protokollanalyseserver.

function interceptResponse(request, response) {
    // Nur APIs bestimmter Pfade melden
    if (!request.path.startsWith('/api/v2/')) {
        return { action: 'passthrough' };
    }
    
    // Anforderungs- und Antwortinformationen sammeln
    var logData = {
        timestamp: new Date().toISOString(),
        request: {
            method: request.method,
            url: request.url,
            headers: request.headers
        },
        response: {
            statusCode: response.statusCode,
            body: response.body
        }
    };
    
    // An den Protokollserver melden (Hinweis: Die Anforderung ist synchron und blockiert die Rückgabe der aktuellen Antwort)
    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);
    }
    
    // Die ursprüngliche Antwort durchlassen
    return { action: 'passthrough' };
}

Beispiel 3: A/B-Tests — Antworten dynamisch ändern

Verwenden Sie einen Zähler, um eine einfache A/B-Aufteilung zu implementieren, die abwechselnd unterschiedliche simulierte Daten zurückgibt.

function interceptRequest(request) {
    if (request.path !== '/api/recommend') {
        return { action: 'passthrough' };
    }
    
    // Den alternativen Zähler aus localStore lesen
    var count = parseInt(localStore.read('ab_counter') || '0');
    count++;
    localStore.write('ab_counter', String(count));
    
    // Abwechselnd unterschiedliche Versionen für gerade und ungerade Zahlen zurückgeben
    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: 'Empfehlungsplan A-1' }, { id: 2, name: 'Empfehlungsplan A-2' }]
                })
            }
        };
    } else {
        return {
            action: 'mock',
            response: {
                statusCode: 200,
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({
                    version: 'B',
                    items: [{ id: 3, name: 'Empfehlungsplan B-1' }, { id: 4, name: 'Empfehlungsplan B-2' }]
                })
            }
        };
    }
}

Beispiel 4: Schutz vor Ratenbegrenzung bei Anforderungen

Zeichnen Sie die Anforderungshäufigkeit derselben API auf und geben Sie einen 429-Fehler zurück, wenn der Schwellenwert überschritten wird.

function interceptRequest(request) {
    if (!request.path.startsWith('/api/')) {
        return { action: 'passthrough' };
    }
    
    var key = 'rate_' + request.path;
    var now = Math.floor(Date.now() / 1000);
    
    // Die Zeit und Anzahl der letzten Anforderung lesen
    var rawData = localStore.read(key);
    var data = rawData ? JSON.parse(rawData) : { count: 0, windowStart: now };
    
    // Wenn das Zeitfenster 60 Sekunden überschreitet, den Zähler zurücksetzen
    if (now - data.windowStart > 60) {
        data = { count: 0, windowStart: now };
    }
    
    data.count++;
    localStore.write(key, JSON.stringify(data));
    
    // Maximal 10 Mal pro 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' };
}

Hinweise

  1. httpClient ist ein synchroner Aufruf: HTTP-Anforderungen, die im Skript gestartet werden, blockieren die Ausführung des Skripts, bis die Anforderung abgeschlossen ist oder das Zeitlimit (15 Sekunden) erreicht ist. Dies wirkt sich auf die Verarbeitungsgeschwindigkeit der ursprünglichen Anforderung aus. Bitte achten Sie auf die in den Protokollen automatisch ausgegebenen Informationen zum Zeitaufwand der Anforderung.

  2. Gemeinsamer Speicher localStore: Alle Skripte teilen sich denselben Speicherplatz. Wenn Sie Daten nach Host isolieren müssen, fügen Sie dem Schlüssel selbst ein Präfix hinzu.

  3. Reihenfolge der Skriptausführung: Mehrere Skripte werden nach Priorität sortiert und ausgeführt. Sobald ein Skript ein anderes Ergebnis als passthrough zurückgibt, werden nachfolgende Skripte übersprungen.

  4. Remote-Skripte: Unterstützt das Laden von Skripten von URLs. Der Inhalt des Remote-Skripts wird beim Starten der Paketerfassung automatisch abgerufen. Wenn der Abruf fehlschlägt, wird das Skript übersprungen.

  5. JSON-Verarbeitung: Der Textkörper der Anforderungen/Antworten besteht aus Zeichenfolgen. Wenn Sie JSON-Daten verarbeiten müssen, verwenden Sie JSON.parse() zum Parsen und JSON.stringify() zur Serialisierung.

  6. Fehlerbehandlung: Es wird empfohlen, try-catch in der Schlüssellogik zu verwenden und Ausnahmen über console.error() zu protokollieren, um zu vermeiden, dass die Abfangkette aufgrund eines Skriptabsturzes unterbrochen wird.

  7. Hilfsfunktionen: Die Engine verfügt über zwei integrierte Hilfsfunktionen:

    • safeJsonParse(str) — Sicheres JSON-Parsen, gibt im Fehlerfall null zurück
    • deepClone(obj) — Tiefe Kopie von Objekten