Переменные и вычисляемые поля

Связывание запросов через переменные {{name}}, экстракторы и DSL вычисляемых полей.

Многошаговые сценарии почти никогда не воспроизводятся из статичных байтов: логин возвращает сессионный токен, производную куку нужно переподписывать при каждой отправке, а nonce должен одновременно совпадать в двух местах. Диалог Replay (API lab → каталог маршрутов → Replay на запросе) при отправке подставляет шаблоны {{…}} в URL, заголовки и тело — из сохранённых переменных цепочки, из значений, извлечённых из предыдущих ответов, и из DSL выражений, который пересчитывает производные токены при каждой отправке.

Связывание запросов переменными {{name}}

Шаблон имеет вид {{name}} (пробелы внутри фигурных скобок допустимы). Имя должно соответствовать [A-Za-z_][A-Za-z0-9_.-]*. При отправке каждое вхождение в черновом URL, заголовках и теле заменяется значением.

  1. В диалоге Replay найдите панель Replay chain variables.
  2. Введите имя и значение, нажмите Add. Список чипов показывает текущие переменные; значения маскируются, пока вы не раскроете секреты.
  3. Сошлитесь на неё в любом редактируемом поле, например Authorization: Bearer {{token}} или /users/{{userId}}, и запустите replay.

Переменные хранятся локально в localStorage под ключом traffic-jam:replay-variables, поэтому они переживают закрытие диалога и перезагрузку страницы и подпитывают следующий запрос в цепочке. Удалить чип можно кнопкой-корзиной.

Если у переменной, на которую есть ссылка, нет значения, шаблон остаётся на месте, а панель показывает бейдж unresolved: name; replay блокируется, пока вы не определите переменную или не уберёте ссылку.

[!NOTE] Replay по умолчанию исключает захваченные учётные данные и запрашивает подтверждение перед методами, изменяющими состояние. Переменные, которые вы вводите, считаются осознанными значениями и отправляются как есть — тестируйте только те системы, на тестирование которых у вас есть разрешение.

Извлечение значений из ответа

После завершения replay под результатом появляется панель Extract response into chain, которая сохраняет одно значение из ответа как переменную рабочей области.

ИсточникВыражениеПримечания
JSON path$.access_token, $.users[0].idВедущий $. необязателен; [n] индексирует массивы. Нестроковые значения сериализуются в JSON. Ошибка, если тело не является JSON или путь отсутствует.
Заголовокx-session-tokenРегистронезависимо; трейлеры ответа тоже просматриваются.
Regex"token":"([^"]+)"Побеждает первая группа захвата; если группы нет — всё совпадение целиком.

Выберите источник, введите выражение и имя переменной, нажмите Extract. При успехе вы получите Saved {{name}} for the next replay; переменная попадает в то же персистентное хранилище, что и добавленные вручную.

Вычисляемые поля: DSL выражений

Обычная подстановка {{name}} — это быстрый путь; всё, что сложнее внутри фигурных скобок, вычисляется как выражение над контекстом захваченного запроса в момент отправки — покрывая производные токены, которые нельзя скопировать дословно, потому что они меняются с каждым запросом.

Ссылки на поля читаются из захваченного запроса:

СсылкаРазрешается в
cookie:nameКука, распарсенная из захваченного заголовка Cookie (побеждает первое вхождение)
header:nameЗаголовок захваченного запроса (регистронезависимо)
query:nameПараметр query (URL-декодированный)
var:nameПеременная цепочки (то же, что и просто name)
bodyТекст тела захваченного запроса (пустой, если обрезано)

Функции (несколько аргументов конкатенируются перед хешированием; для HMAC первый аргумент — ключ):

ФункцияРезультат
sha1(x) / sha256(x) / md5(x)Hex-дайджест в нижнем регистре
hmac-sha1(key, msg) / hmac-sha256(key, msg) / hmac-md5(key, msg)HMAC в hex в нижнем регистре
crc32(x)Беззнаковый CRC-32 в десятичном виде; crc32() без аргумента хеширует тело
base64(x) / base64url(x)Стандартный / URL-safe base64 (без паддинга)
nowMs() / nowSec()Unix timestamp в миллисекундах / секундах
uuid4()Случайный UUID
randomHex(n)n случайных hex-символов (по умолчанию 8)

Пайпы преобразуют значение с помощью |:

ПайпДействие
skip:N (алиас trunc:N)Отбросить первые N символов
take:N (алиас prefix:N)Оставить первые N символов
upper / lowerСмена регистра
urlencodeencodeURIComponent
base64 / base64urlЗакодировать значение

Строковые литералы используют двойные кавычки с экранированием \n, \t и \\; + конкатенирует; скобки группируют. Отсутствующее поле с областью видимости вырождается в пустую строку (с ошибкой для неизвестных областей); отсутствующая обычная переменная сохраняет описанное выше поведение с маркером неразрешённости.

Именованные nonce и многооператорные шаблоны

Операторы, разделённые ;, выполняются по порядку; результат — значение последнего оператора. Присваивание name = expr сохраняет локальную переменную на одну отправку — это способ сгенерировать nonce один раз и переиспользовать его, поскольку один вычисляемый контекст разделяется между всеми полями replay (URL, заголовки и тело видят одни и те же локальные переменные):

{{ p = randomHex:4; p + sha1(secret + cookie:session + p) | skip:4 }}

Второе поле, ссылающееся на {{ p }} в той же отправке, получит идентичный nonce. Локальные переменные затеняют переменные цепочки с тем же именем. randomHex:N и randomB64:N также работают как генераторы с областью видимости (randomHex:4 → 4 hex-символа; randomB64:8 → base64 из 8 случайных байт).

Если вычисление не удаётся (неизвестная функция, пайп или область видимости), шаблон остаётся нетронутым, а ошибка проявляется как Computed field error: …, блокируя отправку.

Разобранный пример: производная кука fgssc

Конструкция из реальной практики: кука fgssca-goldapple — это случайный префикс из 4 hex-символов, за которым следует sha1(appSecret + gsscCookie + prefix) с отброшенными первыми 4 hex-символами. Чтобы воспроизвести её, добавьте секрет приложения как переменную цепочки (например, fgsscSecret), затем поместите это в черновой заголовок Cookie как значение fgssca-goldapple:

{{ p = randomHex:4; p + sha1(fgsscSecret + cookie:gssca-goldapple + p) | skip:4 }}

Результат — 40 hex-символов: префикс из 4 символов плюс обрезанный SHA-1. Поскольку p — именованная локальная переменная, любое другое поле, которому нужен тот же префикс, может сослаться на {{ p }}.

[!TIP] Пока не знаете формулу? Вкладка Signature в API lab перебором находит именно этот класс — prefix + hash(secret + <field> + prefix)[dropN:] наряду с классическими каноникализациями — и сообщает входные данные вывода. См. /docs/ru/api-re/.

Локальные примитивы хеширования

DSL вычисляется синхронно внутри построения payload, поэтому не может вызывать WebCrypto. Хеши работают на локальных синхронных реализациях — SHA-1/SHA-256 по FIPS 180-4, HMAC по RFC 2202/4231 и локальные MD5/HMAC-MD5 (WebCrypto не включает MD5, который всё ещё используют легаси-схемы подписывания в мобильных приложениях) — проверенных на стандартных тестовых векторах. Ничего не покидает рабочую область для вычисления подписи, и та же логика вывода экспортируема в автономный Go-коллектор; см. /docs/ru/collector/. Маскирование значений в панели переменных следует настройке раскрытия рабочей области — см. /docs/ru/security/.

Replay-верстак, лимиты батчей, управление TLS-отпечатком и mTLS описаны в /docs/ru/replay/.

Документация Traffic Jam. Собрано с помощью Hugo.