Контентная маршрутизация

Как изменить URI, с которым запрос уйдёт на upstream, чтобы публичный API и внутренний бэкенд могли использовать разные пути.

Что это

Контентная маршрутизация в данном сценарии — это изменение пути запроса на уровне Application Delivery Controller перед передачей запроса на upstream.

Как работает

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

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

  3. Система формирует URI, с которым запрос будет отправлен на upstream.

    Новый upstream URI можно задать явно через uri или собрать по регулярному выражению через regex_uri. Если используется regex_uri, система сопоставляет исходный путь URI с регулярным выражением и подставляет найденные части в новый upstream URI path через переменные $1, $2, $3 и т.д. Дополнительно плагин может изменить HTTP-метод, Host или заголовки запроса.

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

    Если в плагине дополнительно настроены method, host или headers, запрос уходит на upstream также с изменённым HTTP-методом, Host или заголовками запроса.

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

Предположим, у вас есть публичный API с путём /api/v1/products/SKU-1001, а внутренний бэкенд ожидает запросы по пути /internal/items/SKU-1001.

Менять бэкенд неудобно: этот путь уже используется другими внутренними сервисами. Менять публичный API тоже нельзя: на него уже завязаны клиенты.

Чтобы связать эти части системы, вы добавляете плагин proxy-rewrite и настраиваете преобразование URI перед отправкой запроса на upstream. В результате клиент продолжает обращаться к /api/v1/products/SKU-1001, а upstream получает запрос к /internal/items/SKU-1001.

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

proxy-rewrite

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

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

uri

string

Нет

Поддерживает NGINX variables, например $arg_name

Upstream URI, с которым запрос будет отправлен на upstream. Можно задать новый путь и при необходимости добавить query-параметры.

method

string

Нет

GET, POST, PUT, HEAD, DELETE, OPTIONS, MKCOL, COPY, MOVE, PROPFIND, LOCK, UNLOCK, PATCH, TRACE

HTTP-метод, с которым запрос будет отправлен на upstream.

regex_uri

array
[string]

Нет

Правила для преобразования upstream URI по регулярному выражению на основе исходного URI клиента. В массиве указывается одна или несколько пар, каждая из которых состоит из регулярного выражения и нового URI. Найденные части можно использовать через $1, $2, $3 и т.д.

host

string

Нет

Значение заголовка Host, с которым запрос будет отправлен на upstream.

headers

object

Нет

add, remove, set

Действия с заголовками запроса. Можно добавить, удалить или перезаписать заголовки перед отправкой запроса на upstream. Если передать объект заголовков без add, remove и set, система обработает его как set.

headers.add

object

Нет

Константа, NGINX variables или значения из regex_uri, например $1

Добавляет значения к заголовкам запроса. Если заголовок уже есть, новое значение добавляется к существующему: итоговое значение выглядит как v1,v2, где v1 — значение из плагина, а v2 — значение из исходного запроса.

headers.set

object

Нет

Константа, NGINX variables или значения из regex_uri, например $1

Устанавливает значения заголовков запроса. Если заголовок уже есть, его значение будет перезаписано. Не используйте headers.set для настройки Host: для этого есть отдельный атрибут host.

headers.remove

array
[string]

Нет

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

Удаляет указанные заголовки из запроса перед отправкой на upstream.

use_real_request_
uri_unsafe

boolean

Нет

false

true, false

Позволяет использовать исходный URI запроса без нормализации. Значение true считается небезопасным и должно использоваться только при явной необходимости.

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

Если одновременно настроены uri и regex_uri, приоритет будет у uri. В этом случае правила из regex_uri не будут определять итоговый URI.

Если нужно изменить Host, используйте атрибут host, а не headers.set.

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

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

Через 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": {
      "proxy-rewrite": {
        "...": "ваши настройки плагина"
      }
    },
    "upstream": {
      "...": "ваши настройки upstream"
    }
  }'

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

Через UI

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

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

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

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

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

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

В этом примере система принимает запрос к публичному URI, извлекает из него идентификатор товара и отправляет запрос на другой URI внутреннего бэкенда.

Исходный запрос клиента:

GET /api/v1/products/SKU-1001

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

{
  "plugins": {
    "proxy-rewrite": {
      "regex_uri": [
        "^/api/v1/products/(.*)",
        "/internal/items/$1"
      ]
    }
  }
}

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

GET /internal/items/SKU-1001

Здесь regex_uri сопоставляет исходный URI с регулярным выражением ^/api/v1/products/(.*). Часть пути после /api/v1/products/ попадает в переменную $1. Затем система подставляет это значение в новый URI /internal/items/$1.

В результате клиент продолжает использовать публичный путь /api/v1/products/SKU-1001, а бэкенд получает запрос в своём внутреннем формате: /internal/items/SKU-1001.