Mocks und Fehlerinjektion

Verkehr zu beobachten beantwortet, was eine App tut. Diese Seite handelt von der anderen Hälfte: das Netzwerk etwas antworten zu lassen, was es nie geantwortet hätte, um zu sehen, was die App damit anfängt. Ein Backend, das es noch nicht gibt, ein Endpunkt, der 500 liefert, eine Antwort, die acht Sekunden braucht, eine API, die einfach verschwunden ist.

Alles hier funktioniert auf jeder Plattform, auf der Chute läuft, und alles, was HTTPS berührt, verlangt zuerst Entschlüsselung für diesen Host — eine verschlüsselte Anfrage, die Chute nicht lesen kann, kann es auch nicht beantworten.

Was Chute simulieren kann und was nicht

Chute greift an der Verbindung und an der HTTP-Nachricht ein. Einen Traffic-Shaper hat es nicht:

Kann Einen vorgefertigten Body liefern, einen gewählten Statuscode liefern, vor Anfrage oder Antwort eine feste Verzögerung einlegen, eine Verbindung rundheraus verweigern, HTTP/3-Clients zurück auf TCP zwingen, eine Anfrage an einen anderen Host schicken als den verlangten
Kann nicht Bandbreite begrenzen, Pakete verwerfen oder umsortieren, Jitter hinzufügen, eine Verbindung mittendrin verschlechtern oder eine bestimmte RTT auf Transportebene nachbilden

Es gibt keinen [Throttle]-Abschnitt und nirgends eine Geschwindigkeitsbegrenzung. Wenn Sie eine langsame Leitung brauchen statt einer langsamen Antwort, gehört das zu einem Netzwerk-Conditioner (Apples Network Link Conditioner oder ein Router), nicht zu Chute.

Einen Mechanismus wählen

Zu simulieren Mittel Wo
Ein Antwort-Body, den es noch nicht gibt [Map Local] Mock-Antwort
Genau 503 [URL Rewrite] … reject URL-Umschreibung
Ein leeres 200, ein leeres Bild, ein leeres JSON-Objekt oder -Array reject-200, reject-img / reject-tinygif, reject-dict, reject-array URL-Umschreibung
Jeder andere Status — 401, 429, 500 [Map Local] mit status-code= oder ein http-request-Skript Mock-Antwort, JavaScript-Scripting
Latenz Ein http-request- oder http-response-Skript JavaScript-Scripting
Ein Endpunkt, der schlicht nicht erreichbar ist Eine REJECT-Regel Integrierte Richtlinie
Eine Anfrage, die hängt, bis der Client aufgibt Eine REJECT-DROP-Regel Integrierte Richtlinie
Ein Client, der nicht auf TCP zurückfällt block-quic Verschiedene Optionen
Ein anderes Backend hinter derselben URL [Host] oder [URL Rewrite] im header-Modus Lokale DNS-Zuordnung

Ein vorgefertigter Antwort-Body

[Map Local] beantwortet eine passende Anfrage aus einer Datei oder aus eingebetteten Daten. Bei einem entschlüsselten HTTP/2-Stream wird der echte Server gar nicht gefragt; bei HTTP/1.1 geht die Anfrage trotzdem hinaus, und nur die Antwort wird ersetzt:

[Map Local]
^https://api\.example\.com/v1/profile.* data="/Users/me/mocks/profile.json"
^https://api\.example\.com/v1/flags.* base64="eyJiZXRhIjogdHJ1ZX0="

Drei Dinge entscheiden, ob das funktioniert:

  • Der reguläre Ausdruck passt an beliebiger Stelle der URL, wie bei der URL-Umschreibung: ^https://api\.example\.com/v1/profile deckt den Pfad und jeden folgenden Query-String bereits ab, ein abschließendes .* ist nicht nötig.
  • data= liest das Gerät, auf dem Chute läuft. Auf einem Mac ist das praktisch — Datei ändern, und die nächste Anfrage sieht die Änderung. Auf einem Telefon oder einem Apple TV bedeutet ein Pfad von Ihrem Mac nichts; nehmen Sie dort base64=, oder liefern Sie die Datei über HTTP aus und nutzen Sie die URL-Umschreibung.
  • Der Status ist 200 OK, sofern Sie nicht status-code= setzen, und nach der Antwort wird die Verbindung geschlossen. Antwort-Header gehören in header="Key: value|…".

Der Body unterstützt die Vorlagenvariablen {{ "{{url}}" }}, {{ "{{host}}" }}, {{ "{{path}}" }}, {{ "{{method}}" }} und {{ "{{ua}}" }}, was für einen Mock reicht, der zurückspiegelt, wonach gefragt wurde.

Ein Fehlerstatus

Für 503 braucht es kein Skript — eine URL-Umschreibung im reject-Modus liefert HTTP/1.1 503:

[URL Rewrite]
^https://api\.example\.com/v1/orders.* _ reject

Die verwandten Modi decken die übrigen Formen von „nichts Brauchbares“ ab: reject-200 (200 mit leerem Body), reject-img und reject-tinygif (ein 1×1-GIF), reject-dict ({} als JSON, 200), reject-array ([] als JSON, 200). Alle greifen bei HTTPS nur, wenn dieser Host gerade entschlüsselt wird.

Für jeden anderen Statuscode ist eine Mock-Regel mit status-code= der kürzeste Weg:

[Map Local]
^https://api\.example\.com/v1/orders data-type=text data="rate limited" status-code=429 header="Retry-After: 30"

Muss die Antwort von der Anfrage abhängen, beantwortet stattdessen ein http-request-Skript die Anfrage direkt, ohne den Server zu kontaktieren:

[Script]
Fail429 = type=http-request, script-path=/Users/me/mocks/fail429.js, pattern=^https://api\.example\.com/v1/orders
// fail429.js — antworten, ohne den Server zu kontaktieren
$done({
    response: {
        status: 429,
        headers: {
            "Content-Type": "application/json",
            "Retry-After": "30"
        },
        body: JSON.stringify({ error: "rate_limited" })
    }
})

Das pattern eines Skripts passt an beliebiger Stelle der URL, wie bei den Umschreibungsfamilien — ein Präfix wie ^https://api\.example\.com/v1/orders genügt, ein abschließendes .* ist nicht nötig.

Auf HTTP/1.1 trägt die Statuszeile die Standard-Statusmeldung (Reason Phrase) des Codes (HTTP/1.1 429 Too Many Requests); ein Code, dem das Register keinen Namen gibt, etwa 599, erhält keine (HTTP/1.1 599).

Latenz

Ein Skript, das einen Timer anmeldet, bleibt am Leben, bis es $done() aufruft — der Timer ist also eine Verzögerung. (Ein Skript, das nichts anmeldet, wartet nicht: Es lässt die Nachricht durch, sobald es zurückkehrt.)

[Script]
SlowAPI = type=http-response, script-path=/Users/me/mocks/slow.js, pattern=^https://api\.example\.com/v1/, timeout=15
// slow.js — die echte Antwort acht Sekunden zu spät zurückgeben
setTimeout(function () {
    $done({})
}, 8)

Das Budget ist das timeout des Skripts selbst: standardmäßig 5 Sekunden, alles über 30 wird auf 30 gekappt. Ein Skript, das bei Ablauf des Timeouts kein $done() gerufen hat, gilt als durchgereicht (Passthrough) — die Nachricht läuft unverändert weiter —, eine Verzögerung länger als das Timeout scheitert also nicht laut, sie verzögert nur nicht mehr. Setzen Sie timeout über die gewünschte Verzögerung, wie im Beispiel.

type=http-request verzögert, bevor der Server kontaktiert wird (die App sieht einen langsamen Roundtrip), type=http-response danach (der Server war schnell, die App wartet trotzdem).

Ein Endpunkt, der einfach weg ist

Ein Mock ersetzt eine Antwort; eine REJECT-Regel verweigert die Verbindung. Sie wirkt auf Verbindungsebene, deckt damit jedes Protokoll ab statt nur HTTP, und braucht keine Entschlüsselung:

[Rule]
DOMAIN-SUFFIX,api.example.com,REJECT

Die REJECT-Varianten antworten unterschiedlich, und das ist auch hier nützlich. REJECT-DROP antwortet nie, der Client wartet also, bis er in ein Timeout läuft — so sieht ein toter Server aus. REJECT-200, REJECT-DICT, REJECT-ARRAY, REJECT-TINYGIF / REJECT-IMG und REJECT-VIDEO beantworten eine unverschlüsselte oder entschlüsselte HTTP/1-Anfrage mit einem synthetischen 200 (leer, {}, [], ein 1×1-GIF, ein leeres MP4). REJECT, REJECT-TINYGIF und REJECT-IMG werden für 30 Sekunden zu REJECT-DROP, sobald ein Host mehr als 50-mal in 30 Sekunden abgelehnt wurde; REJECT-NO-DROP und die anderen Varianten nie. Siehe Integrierte Richtlinie. Für HTTP-Anfragen ersetzt show-error-page-for-reject = true die nackte Ablehnung durch eine lesbare Fehlerseite, sodass im Browser sofort klar ist, dass die Blockade Ihre war.

So prüfen Sie auch, ob es überhaupt einen Ausweichpfad gibt — verweigern Sie den primären Host und sehen Sie, ob die App nach dem sekundären greift oder nur einen Ladekreis zeigt.

Einen Client von HTTP/3 herunterholen

QUIC läuft über UDP und Chute kann es nicht entschlüsseln, eine App auf HTTP/3 ist für jeden Mechanismus dieser Seite also unsichtbar. Verweigert man ihre QUIC-Flüsse, versuchen es kompatible Clients erneut über TCP, wo all das funktioniert:

[General]
block-quic = on

auto verweigert QUIC nur, wenn der Fluss zu einem Proxy geht; on verweigert überall, DIRECT eingeschlossen. Für Verkehr, der durch TUN kommt, antwortet Chute auf einen verweigerten QUIC-Fluss mit ICMP Port Unreachable, sodass der Client sofort zurückfällt, statt ein Timeout abzuwarten.

Die Anfrage woandershin schicken

Zwei Wege auf zwei Ebenen:

[Host]
api.example.com = 10.0.0.5

Eine [Host]-Zuordnung beantwortet die DNS-Auflösung mit einer Adresse Ihrer Wahl — einer Staging-Maschine, oder einer Adresse, die nirgendwohin führt, wenn Sie eine Verbindung wollen, die in ein Timeout läuft statt abgewiesen zu werden. Sie gilt für jedes Protokoll und braucht keine Entschlüsselung. Leeren Sie danach den DNS-Cache.

[URL Rewrite]
^https://api\.example\.com/v1/(.*) https://staging.example.com/v1/$1 header

Der header-Modus schreibt die Anfrage an Ort und Stelle um und passt den Host-Header entsprechend an. Das ist HTTP-Ebene und braucht bei HTTPS die Entschlüsselung. Der Client erfährt von der Umschreibung nichts, solange die Anfrage ihren Host behält. Eine entschlüsselte HTTPS-Anfrage ist an den Host gebunden, an den sie gesendet wurde, daher wird eine Regel, die einen anderen Host nennt — wie die obige —, mit einem 307 auf die neue URL beantwortet, dem der Client selbst folgt; genauso antwortet Chute überall sonst, wo sich das Ziel nicht an Ort und Stelle umschreiben lässt.

Bestätigen, dass es gegriffen hat

Eine Regel, die nie passt, sieht genauso aus wie eine, die passte und nichts tat — das ist der typische Fehlerfall für alles auf dieser Seite.

  • Umschreibungen und Mocks: Die Seite Regeln der Web-Konsole listet jede Regel für URL-Umschreibung, Header-Umschreibung, Body-Umschreibung und Mock-Antwort, die in diesem Lauf gegriffen hat, mit Zähler. Nicht in der Liste heißt nie gepasst. Dieselben Daten liegen in rewrite_hits von GET /api/rules.
  • Pro Verbindung: Öffnen Sie die Verbindung in der Konsole und lesen Sie ihre Zeilen Angewendete Umschreibungen, die die Regel in ihren eigenen Worten nennen. In Dashboard zählt der Tab Allgemein der Verbindung sie als Ausgelöst unter Regeln und nennt sie in der Liste Ausgelöste Regeln.
  • Skripte tauchen in dieser Tabelle nicht auf. Der Beleg eines Skripts ist seine eigene Ausgabe: console.log-Zeilen landen im Protokoll, lesbar auf der Seite Protokolle der Konsole oder mit GET /api/logs. Sie werden auf der Stufe verbose geschrieben, heben Sie also zuerst loglevel auf verbose an — PUT /api/loglevel erledigt das ohne Neuladen; console.warn und console.error erscheinen auf der Standardstufe. Jede Zeile wird auf 256 Zeichen gekürzt, Zugangsdaten werden maskiert.

Aufräumen

Regeln, die aus der Konsole, aus Dashboard oder über POST /api/rewrites/:family hinzugefügt wurden, leben in der laufenden Engine und sind beim nächsten Neustart weg — ideal für ein Experiment und ein schlechter Ort für etwas, auf das Sie sich verlassen. Regeln in der Konfigurationsdatei überstehen Neustarts, was sie zu einem guten Ort für einen Mock macht und zu etwas, das man auf keinen Fall vergessen darf: Eine [Map Local]-Zeile, die in einer Konfiguration stehen bleibt, beantwortet Wochen später immer noch Anfragen — und sieht dabei genau aus wie ein kaputter Server.

S. Smart Rabbit LLC © All Rights Reserved            updated 2026-09-30 15:11:19

Diese Seite ist eine Übersetzung der englischen Version. Bei Abweichungen ist die englische Version maßgeblich.

results matching ""

    No results matching ""