Работа с payload

Как заменить или частично изменить body ответа перед возвратом клиенту.

Эта статья — про изменение response body без разбора его структуры: Application Delivery Controller либо заменяет тело ответа целиком, либо находит в нём текстовые фрагменты по регулярному выражению и заменяет их.

Если вам нужно преобразовать body по шаблону (например, разобрать XML и собрать из его полей JSON), используйте плагин body-transformer по инструкции из Парсинг и модификация.

Что это

Работа с payload — это изменение тела ответа на уровне Application Delivery Controller перед тем, как ответ будет передан клиенту.

Система может полностью заменить response body или найти в нём фрагменты с помощью регулярного выражения и заменить их.

Как работает

  1. Клиент отправляет запрос.

  2. Наша система получает запрос и сопоставляет его с Route, в котором настроен плагин response-rewrite.

  3. Система отправляет запрос на upstream.

  4. Upstream возвращает ответ.

  5. Система проверяет настройки response-rewrite.

    Если настроен атрибут body, система заменяет тело ответа целиком.

    Если настроен атрибут filters, система ищет в исходном body фрагменты с помощью регулярного выражения и заменяет их на новое значение.

    Если настроен vars, изменения применяются только к ответам, которые соответствуют заданным условиям, например только к ответам со статусом 200.

  6. Система возвращает клиенту уже изменённый ответ.

Response-rewrite может изменять не только ответ upstream, но и ответ, который сформировала наша система, — например если другой плагин отклонил запрос до обращения к бэкенду.

Когда пригодится

Предположим, у вас есть бэкенд, который возвращает технический ответ:

{
  "status": "ok",
  "internal_code": "ORDER_CREATED",
  "message": "created"
}

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

Вы добавляете response-rewrite и настраиваете новое тело ответа. Бэкенд продолжает возвращать прежний формат, а клиент получает публичный payload:

{
  "result": "success",
  "message": "Order created"
}

Какой плагин используется

response-rewrite

Атрибуты плагина

Атрибут Тип Обязательный Значение по умолчанию Допустимые значения Что задаёт

status_code

integer

Нет

—

От 200 до 598

Новый HTTP-статус ответа. Если не задан, сохраняется исходный статус.

body

string

Нет

—

—

Новое тело ответа. При использовании body система сбрасывает заголовок Content-Length, потому что тело ответа изменяется. Нельзя использовать вместе с filters.

body_base64

boolean

Нет

false

true, false

Показывает, что значение body передано в формате base64 и должно быть декодировано перед отправкой клиенту. Не используется для декодирования ответа upstream.

headers

object

Нет

—

add, remove, set

Действия с заголовками ответа. Для работы с payload может пригодиться, если вместе с body нужно изменить, например, Content-Type.

headers.add

array
[string]

Нет

—

Строки в формате "Header-Name: value"

Добавляет заголовки к ответу. Значение можно задать константой или NGINX variable. Если такой заголовок уже есть, новое значение будет добавлено к существующему.

headers.set

object

Нет

—

Константа или NGINX variable

Устанавливает значения заголовков ответа. Если заголовок уже есть, его значение будет перезаписано.

headers.remove

array
[string]

Нет

—

Имена заголовков

Удаляет указанные заголовки из ответа.

vars

array
[array]

Нет

—

Условия в формате lua-resty-expr

Условия, при которых будет выполнено изменение ответа.

filters

array
[object]

Нет

—

—

Список правил, которые изменяют response body: находят фрагмент с помощью регулярного выражения и заменяют его на другое значение. Нельзя использовать вместе с body.

filters.regex

string

Да, если задан filters

—

Регулярное выражение

Шаблон для поиска фрагмента в response body.

filters.scope

string

Нет

once

once, global

Область замены: только первое совпадение или все совпадения в body.

filters.replace

string

Да, если задан filters

—

—

Значение, на которое нужно заменить найденный фрагмент.

filters.options

string

Нет

jo

Опции регулярного выражения Lua NGINX module

Параметры выполнения регулярного выражения.

Что важно учесть

body и filters нельзя использовать одновременно. Если нужно полностью заменить тело ответа, используйте body. Если нужно изменить только часть исходного body, используйте filters.

Действия с заголовками выполняются в следующем порядке: add, затем remove, затем set.

body_base64 применяется только к значению, которое вы задали в body. Этот атрибут не декодирует тело ответа, полученное от upstream.

Если вы меняете формат body, например возвращаете JSON вместо plain text, настройте соответствующий Content-Type через headers.set.

Если изменения должны применяться не ко всем ответам, используйте vars. Например, можно заменить body только для ответов со статусом 200.

response-rewrite может менять не только ответ upstream, но и ответ, который сформировала наша система. Под ответом, сформированным системой, имеется в виду ответ, который система вернула сама, без обращения к бэкенду. Например, так может произойти, если другой плагин заблокировал запрос или вернул ошибку авторизации.

Как подключить плагин

Через API

Плагин можно добавить к Route через Admin API. Для этого отправьте запрос на создание или обновление Route:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
  -H "X-API-KEY: ${admin_key}" \
  -d '{
    "id": "route-id",
    "uri": "/example",
    "plugins": {
      "response-rewrite": {
        "...": "ваши настройки плагина"
      }
    },
    "upstream": {
      "...": "ваши настройки upstream"
    }
  }'

Здесь id — идентификатор Route, uri — путь, по которому запрос попадает в Route, plugins.response-rewrite содержит конфигурацию плагина, а upstream — настройки бэкенд-серверов.

Через UI

  1. Откройте раздел Маршруты и нажмите + Добавить.

  2. В настройках маршрута (Route) перейдите в раздел Плагины.

  3. Нажмите + Добавить и выберите response-rewrite.

  4. Укажите конфигурацию плагина как JSON-объект.

  5. Сохраните созданный маршрут (Route). Он будет добавлен с подключённым плагином.

Пример конфигурации плагина

В этом примере система полностью заменяет body ответа от upstream и возвращает клиенту публичный JSON.

Ответ upstream:

{
  "status": "ok",
  "internal_code": "ORDER_CREATED",
  "message": "created"
}

Настройка плагина response-rewrite:

{
  "plugins": {
    "response-rewrite": {
      "body": "{\"result\":\"success\",\"message\":\"Order created\"}",
      "headers": {
        "set": {
          "Content-Type": "application/json"
        }
      },
      "vars": [
        ["status", "==", 200]
      ]
    }
  }
}

После преобразования клиент получит такой ответ:

{
  "result": "success",
  "message": "Order created"
}

Здесь body задаёт новое тело ответа, headers.set устанавливает Content-Type: application/json, а vars ограничивает применение правила только ответами со статусом 200.