Skip to content

Свои заголовки ​

Иногда к каждому запросу нужно добавить заголовок, которого нет в спецификации WB: креденшелы шлюза или корпоративного прокси, стоящего перед API, идентификатор трассировки, метка окружения. Каждый клиент умеет добавлять такие заголовки — механизм свой в каждом языке, и ниже разобраны все восемь.

Что сюда не относится ​

Две вещи стоит отделить сразу, иначе легко добавить заголовок, который клиент и так проставляет.

Токен WB. Заголовок Authorization клиент формирует сам из токена — см. Аутентификацию. Не собирайте его руками через механизмы этой страницы: в части языков (Go) это приведёт к двум заголовкам Authorization в одном запросе.

Заголовки, описанные в спецификации. Если заголовок объявлен в спецификации операции, генератор уже превратил его в обычный аргумент метода. В WB такие есть: X-Nm-Id и X-Photo-Number у postV3MediaFile в под-модуле items. Передавайте их аргументами, а не как «свои».

Остаётся всё остальное — заголовки, о которых спецификация не знает. Их и добавляем.

Заголовки на весь клиент ​

Самый частый случай: заголовок нужен всем запросам. Задаётся один раз при сборке клиента.

python
from wb_api_client.items import Configuration, ApiClient
from wb_api_client.items.api import ItemsApi

client = ApiClient(Configuration(access_token="<ваш JWT WB>"))
client.set_default_header("X-Gateway-Token", "<креденшелы шлюза>")
client.set_default_header("X-Request-Source", "erp-sync")

api = ItemsApi(client)
ts
import {
  Configuration,
  ItemsApi,
} from "@valeryverkhoturov/wb-api-client/items";

const cfg = new Configuration({
  baseOptions: {
    headers: {
      "X-Gateway-Token": "<креденшелы шлюза>",
      "X-Request-Source": "erp-sync",
    },
  },
});
cfg.setAccessToken("<ваш JWT WB>");

const api = new ItemsApi(cfg);
go
import wbitems "github.com/ValeryVerkhoturov/wb-api-client-go/items"

cfg := wbitems.NewConfiguration()
cfg.SetAccessToken("<ваш JWT WB>")
cfg.AddDefaultHeader("X-Gateway-Token", "<креденшелы шлюза>")
cfg.AddDefaultHeader("X-Request-Source", "erp-sync")

client := wbitems.NewAPIClient(cfg)
java
import io.github.valeryverkhoturov.wbapi.items.ApiClient;
import io.github.valeryverkhoturov.wbapi.items.api.ItemsApi;

ApiClient client = new ApiClient();
client.setAccessToken("<ваш JWT WB>");
client.addDefaultHeader("X-Gateway-Token", "<креденшелы шлюза>");
client.addDefaultHeader("X-Request-Source", "erp-sync");

ItemsApi api = new ItemsApi(client);
php
use ValeryVerkhoturov\WbApiClient\Items\Configuration;
use ValeryVerkhoturov\WbApiClient\Items\Api\ItemsApi;
use GuzzleHttp\Client;

$config = (new Configuration())
    ->setAccessToken('<ваш JWT WB>');

// У Configuration в PHP нет реестра заголовков — их держит Guzzle-клиент.
$http = new Client([
    'headers' => [
        'X-Gateway-Token' => '<креденшелы шлюза>',
        'X-Request-Source' => 'erp-sync',
    ],
]);

$api = new ItemsApi($http, $config);
bsl
#Использовать "wb-api-client"

Настройки = Новый Конфигурация();
Настройки.УстановитьТокен("<ваш JWT WB>");
Настройки.ДополнительныеЗаголовки.Вставить("X-Gateway-Token", "<креденшелы шлюза>");
Настройки.ДополнительныеЗаголовки.Вставить("X-Request-Source", "erp-sync");

Клиент = Новый ItemsApi(Настройки);
csharp
using ValeryVerkhoturov.WbApiClient.Items.Api;
using ValeryVerkhoturov.WbApiClient.Items.Client;

var config = new Configuration();
config.SetAccessToken("<ваш JWT WB>");
config.DefaultHeaders["X-Gateway-Token"] = "<креденшелы шлюза>";
config.DefaultHeaders["X-Request-Source"] = "erp-sync";

var api = new ItemsApi(config);
rust
use wb_api_client::items::apis::configuration::Configuration;

// У Configuration в Rust нет реестра заголовков — их держит reqwest-клиент.
let mut headers = reqwest::header::HeaderMap::new();
headers.insert("X-Gateway-Token", "<креденшелы шлюза>".parse().unwrap());
headers.insert("X-Request-Source", "erp-sync".parse().unwrap());

let mut cfg = Configuration::new();
cfg.set_access_token("<ваш JWT WB>");
cfg.client = reqwest::Client::builder()
    .default_headers(headers)
    .build()
    .unwrap();

Заголовки живут на экземпляре Configuration / ApiClient — а он свой у каждого под-модуля. Используете items и orders_fbs — задайте заголовки обоим; подробнее про это в разделе «Один токен на несколько под-модулей».

Заголовки на один запрос ​

Отдельный заголовок для одного вызова умеют не все клиенты: это зависит от того, что сгенерировал openapi-generator для конкретного языка.

ЯзыкПоддержка на уровне вызова
Pythonда — именованный параметр _headers= у каждого метода
TypeScriptда — последний аргумент RawAxiosRequestConfig
Goнет — методы не принимают заголовки
Javaнет
PHPнет
C#нет
OneScriptнет — Заголовки собираются внутри метода
Rustнет — методы принимают только &Configuration
python
# Внимание: заголовки по умолчанию перекрывают _headers при совпадении имени.
tags = api.get_v2_tags(_headers={"X-Correlation-Id": "9f1c-…"})
ts
// Здесь наоборот: заголовок вызова перекрывает и baseOptions, и Authorization.
const tags = await api.getV2Tags({
  headers: { "X-Correlation-Id": "9f1c-…" },
});

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

Что чем перекрывается ​

Порядок слияния у каждого генератора свой, и он не везде интуитивен. Проверено по сгенерированному коду:

ЯзыкПорядок (побеждает правый)Особенность
Python_headers → заголовки по умолчаниюУмолчания побеждают: default_headers применяются поверх _headers
TypeScriptавторизация → baseOptions.headers → заголовки вызовазаголовком конфигурации можно перебить и Authorization
Go—используется Header.Add, то есть добавление, а не замена: дубль имени даст два заголовка
JavadefaultHeaderMap поверх заголовков операциизамена по имени
PHPзаголовки запроса → дефолты Guzzleклиентские дефолты Guzzle применяются, только если заголовка ещё нет
C#DefaultHeaders → заголовки операциизамена по имени
OneScriptAccept/User-Agent/Authorization → ДополнительныеЗаголовки → заголовки операцииСоответствие.Вставить заменяет значение
Rustdefault_headers клиента → заголовки операциизаголовок, который ставит операция, перекрывает дефолт reqwest-клиента

Практический вывод один: не используйте механизмы этой страницы, чтобы переопределить заголовок, который клиент уже ставит сам. Для User-Agent есть штатная настройка в каждом языке, для Authorization — сеттер токена.

Секреты в заголовках ​

SecretString оборачивает только токен WB. Креденшелы шлюза или партнёрского сервиса — обычные строки, и клиент их не маскирует: в логе HTTP-клиента или в дампе конфигурации они будут видны целиком.

Поэтому к ним применимы те же правила, что и к токену WB:

  1. Держите значение в секрет-менеджере (Vault, SSM, GitHub Actions secret), а не в исходниках.
  2. Читайте в переменную окружения на старте процесса и собирайте клиент один раз.
  3. Проверьте, что ваш логгер запросов не пишет заголовки целиком — либо внесите свои имена заголовков в список маскируемых.

Если вы логируете запросы через middleware, добавьте имена этих заголовков в тот же фильтр, где у вас уже лежит Authorization.

wb-api-client mascot

Распространяется под лицензией Apache 2.0.