Работа с 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.