Имитация и внедрение сбоев

Наблюдение за трафиком отвечает на вопрос, что приложение делает. Эта страница — о другой половине: заставить сеть ответить то, чего она никогда бы не ответила, и посмотреть, как приложение с этим справится. Бэкенд, которого ещё нет; эндпоинт, отдающий 500; ответ, приходящий через восемь секунд; API, который попросту исчез.

Всё описанное работает на любой платформе, где работает Chute, а всё, что касается HTTPS, требует сначала включить расшифровку для этого хоста: зашифрованный запрос, который Chute не может прочитать, он не может и отработать за сервер.

Что Chute может имитировать, а что нет

Chute вмешивается на уровне соединения и HTTP-сообщения. Формирователя трафика у него нет, поэтому:

Может Вернуть заготовленное тело, вернуть выбранный код состояния, добавить фиксированную задержку перед запросом или ответом, наотрез отказать в соединении, вернуть клиентов с HTTP/3 на TCP, отправить запрос не тому хосту, который был запрошен
Не может Ограничить полосу, терять или переставлять пакеты, добавлять джиттер, ухудшать соединение по ходу дела или воспроизводить конкретный RTT на транспортном уровне

Секции [Throttle] в конфигурации нет, ограничения скорости нет нигде. Если нужен медленный канал, а не медленный ответ, это дело сетевого кондиционера (Network Link Conditioner от Apple или маршрутизатор), а не Chute.

Выбрать механизм

Что имитировать Чем Где описано
Тело ответа, которого ещё нет [Map Local] Имитация ответов
Ровно 503 [URL Rewrite]reject Перезапись URL
Пустой 200, пустая картинка, пустой объект JSON reject-200, reject-img, reject-dict Перезапись URL
Любой другой статус — 401, 429, 500 Сценарий http-request Сценарии JS
Задержка Сценарий http-request или http-response Сценарии JS
Эндпоинт, до которого просто не достучаться Правило REJECT Встроенные политики
Клиент, который не откатывается на TCP block-quic Прочие параметры
Другой бэкенд за тем же URL [Host] или режим header у [URL Rewrite] Локальное сопоставление DNS

Заготовленное тело ответа

[Map Local] отвечает на подходящий запрос из файла или из встроенного base64, не спрашивая настоящий сервер:

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

Сработает это или нет, решают три вещи:

  • Регулярное выражение должно совпасть со всем URL, а не с его частью. Заканчивайте шаблон на .*, если только вам не нужен URL вовсе без строки запроса.
  • data= читает то устройство, на котором работает Chute. На Mac это удобно: правите файл — и следующий запрос видит изменение. На телефоне или Apple TV путь с вашего Mac не значит ничего; там используйте base64= либо отдавайте файл по HTTP и применяйте перезапись URL.
  • Статус всегда 200 OK. У [Map Local] нет способа его задать, а после ответа соединение закрывается. Для любого другого статуса берите сценарий — см. ниже.

Тело поддерживает шаблонные переменные {{ "{{url}}" }}, {{ "{{host}}" }}, {{ "{{path}}" }}, {{ "{{method}}" }} и {{ "{{ua}}" }}, чего достаточно, чтобы сделать имитацию, отражающую то, о чём её спросили.

Код ошибки

Для 503 сценарий не нужен: перезапись URL в режиме reject возвращает HTTP/1.1 503:

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

Соседние режимы покрывают остальные формы «ничего полезного»: reject-200 (200 с пустым телом), reject-img (GIF 1×1), reject-dict ({} как JSON, 200). Все они применяются к HTTPS только тогда, когда этот хост расшифровывается.

Для любого другого кода состояния сценарий http-request замыкает запрос на себя:

[Script]
Fail429 = type=http-request, script-path=/Users/me/mocks/fail429.js, pattern=^https://api\.example\.com/v1/orders
// fail429.js — ответить, не обращаясь к серверу
$done({
    response: {
        status: 429,
        headers: {
            "Content-Type": "application/json",
            "Retry-After": "30"
        },
        body: JSON.stringify({ error: "rate_limited" })
    }
})

pattern сценария совпадает в любом месте URL, в отличие от семейств перезаписи: префикса вроде ^https://api\.example\.com/v1/orders достаточно, завершающая .* не нужна.

На пути HTTP/1.1 строка состояния пишется с пояснением OK, каким бы ни был код (HTTP/1.1 429 OK). Клиенты читают число, а не текст, так что это чисто косметика — но именно так это выглядит в сыром дампе.

Задержка

Сценарий удерживает сообщение, пока не вызовет $done(), поэтому таймер — это и есть задержка:

[Script]
SlowAPI = type=http-response, script-path=/Users/me/mocks/slow.js, pattern=^https://api\.example\.com/v1/, timeout=15
// slow.js — вернуть настоящий ответ на восемь секунд позже
setTimeout(function () {
    $done({})
}, 8)

Бюджет — это собственный timeout сценария: по умолчанию 5 секунд, всё свыше 30 урезается до 30. Сценарий, не вызвавший $done() к истечению таймаута, считается пропуском — сообщение идёт дальше без изменений, — так что задержка длиннее таймаута не падает с грохотом, она просто перестаёт задерживать. Ставьте timeout больше нужной задержки, как в примере.

type=http-request задерживает до обращения к серверу (приложение видит медленный оборот), type=http-response — после (сервер был быстр, а приложение всё равно ждёт).

Эндпоинт, которого просто нет

Имитация подменяет ответ, а правило REJECT отказывает в соединении. Оно работает на уровне соединения, поэтому охватывает любой протокол, а не только HTTP, и расшифровки не требует:

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

REJECT-DROP, REJECT-TINYGIF и REJECT-NO-DROP принимаются для совместимости и ведут себя как обычный REJECT. Для HTTP-запросов show-error-page-for-reject = true заменяет сухой отказ читаемой страницей ошибки, и в браузере сразу видно, что блокировка ваша.

Так же проверяют, есть ли вообще запасной путь: отклоните основной хост и посмотрите, потянется ли приложение ко второму или просто зависнет.

Снять клиента с HTTP/3

QUIC работает поверх UDP, и Chute его не расшифровывает, поэтому приложение на HTTP/3 невидимо для всех механизмов этой страницы. Отклонение его QUIC-потоков заставляет совместимые клиенты повторить попытку по TCP, где всё это работает:

[General]
block-quic = on

auto отклоняет QUIC, только когда поток идёт на прокси; on отклоняет везде, включая DIRECT. Для трафика, приходящего через TUN, Chute отвечает на отклонённый QUIC-поток сообщением ICMP Port Unreachable, чтобы клиент откатился сразу, а не ждал таймаута.

Отправить запрос в другое место

Два способа на двух уровнях:

[Host]
api.example.com = 10.0.0.5

Сопоставление [Host] отвечает на DNS-запрос выбранным вами адресом — стенда или адреса, ведущего в никуда, если нужно соединение, уходящее в таймаут, а не отвергнутое. Оно действует для любого протокола и не требует расшифровки. После изменения очистите кэш DNS.

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

Режим header переписывает запрос на месте и поправляет заголовок Host, так что клиент и не узнает, что его перенаправили. Это уровень HTTP, и для HTTPS нужна расшифровка. Если назначение переписать на месте нельзя, Chute откатывается к ответу 307 на новый URL.

Убедиться, что оно сработало

Правило, которое ни разу не совпало, выглядит ровно так же, как правило, которое совпало и ничего не сделало, — именно так эта страница целиком и подводит.

  • Перезаписи и имитации: страница Правила в Веб-консоли перечисляет каждое правило URL Rewrite, Header Rewrite, Body Rewrite и Map Local, сработавшее за этот запуск, со счётчиком. Нет в списке — значит ни разу не совпало. Те же данные лежат в rewrite_hits у GET /api/rules.
  • По соединению: откройте соединение в консоли или в Dashboard и прочтите строки Применённые перезаписи, где правило названо его собственными словами.
  • Сценариев в этой таблице нет. Свидетельство сценария — его собственный вывод: строки console.log попадают в журнал и читаются на странице Журналы консоли или через GET /api/logs.

Убрать за собой

Правила, добавленные из консоли, из Dashboard или через POST /api/rewrites/:family, живут в работающем ядре и исчезают при следующем перезапуске — идеально для опыта и очень плохо для того, на что вы полагаетесь. Правила в файле конфигурации переживают перезапуски, что делает файл хорошим местом для имитации и очень плохой вещью, чтобы о ней забыть: строка [Map Local], оставленная в конфигурации, будет отвечать на запросы и через несколько недель, а выглядеть это будет в точности как сломанный сервер.

S. Smart Rabbit LLC © All Rights Reserved            updated 2026-09-05 01:01:14

Эта страница — перевод английской версии. При расхождениях приоритет имеет английская версия.

results matching ""

    No results matching ""