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 | reject-200, reject-img, reject-dict |
URL-Umschreibung |
| Jeder andere Status — 401, 429, 500 | Ein http-request-Skript |
JS-Skripting |
| Latenz | Ein http-request- oder http-response-Skript |
JS-Skripting |
| Ein Endpunkt, der schlicht nicht erreichbar ist | Eine REJECT-Regel |
Eingebaute Richtlinie |
| Ein Client, der nicht auf TCP zurückfällt | block-quic |
Sonstige 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 eingebettetem Base64, ohne den echten Server zu fragen:
[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 muss auf die ganze URL passen, nicht auf einen Teil. Lassen Sie das Muster auf
.*enden, sofern Sie nicht ausdrücklich eine URL ganz ohne Query-String treffen wollen. 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 dortbase64=, oder liefern Sie die Datei über HTTP aus und nutzen Sie die URL-Umschreibung.- Der Status ist immer
200 OK.[Map Local]hat keine Möglichkeit, einen zu setzen, und nach der Antwort wird die Verbindung geschlossen. Für jeden anderen Status nehmen Sie ein Skript — siehe unten.
Der Body unterstützt die Template-Variablen {{ "{{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 (ein 1×1-GIF), reject-dict ({} als JSON, 200). Alle greifen bei HTTPS nur, wenn dieser Host gerade entschlüsselt wird.
Für jeden anderen Statuscode kürzt ein http-request-Skript die Anfrage ab:
[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, anders als bei den Rewrite-Familien — ein Präfix wie ^https://api\.example\.com/v1/orders genügt, ein abschließendes .* ist nicht nötig.
Auf dem HTTP/1.1-Pfad wird die Statuszeile unabhängig vom Code mit der Begründung
OKgeschrieben (HTTP/1.1 429 OK). Clients lesen die Zahl, nicht den Text, das ist also kosmetisch — aber genau so steht es in einem rohen Mitschnitt.
Latenz
Ein Skript hält die Nachricht auf, bis es $done() aufruft — ein Timer ist also eine Verzögerung:
[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 Durchreiche — 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 eine langsame Runde), 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
REJECT-DROP, REJECT-TINYGIF und REJECT-NO-DROP werden aus Kompatibilitätsgründen akzeptiert und verhalten sich alle wie ein einfaches REJECT. 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 dreht.
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 zieht den Host-Header mit, sodass der Client nie erfährt, dass er umgeleitet wurde. Das ist HTTP-Ebene und braucht bei HTTPS die Entschlüsselung. Lässt sich das Ziel nicht an Ort und Stelle umschreiben, weicht Chute darauf aus, mit einem 307 auf die neue URL zu antworten.
Bestätigen, dass es gegriffen hat
Eine Regel, die nie passt, sieht genauso aus wie eine, die passte und nichts tat — das ist die Art, wie diese ganze Seite scheitert.
- Rewrites und Mocks: Die Seite Regeln der Web-Konsole listet jede URL-, Header-, Body-Rewrite- und Map-Local-Regel, die in diesem Lauf gegriffen hat, mit Zähler. Nicht in der Liste heißt nie gepasst. Dieselben Daten liegen in
rewrite_hitsvonGET /api/rules. - Pro Verbindung: Öffnen Sie die Verbindung in der Konsole oder in Dashboard und lesen Sie ihre Zeilen Angewandte Rewrites, die die Regel in ihren eigenen Worten nennen.
- 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 mitGET /api/logs.
Aufräumen
Regeln, die aus der Konsole, aus Dashboard oder über POST /api/rewrites/:family hinzugefügt wurden, leben im laufenden Kernel 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.
Diese Seite ist eine Übersetzung der englischen Version. Bei Abweichungen ist die englische Version maßgeblich.