Nginx устанавливает оставшееся количество для limit_req в заголовке X-RateLimit-Remaining

На самом деле я немного удивлен, что через пару часов работы в Google не смог найти ничего, но проблема такова:

Я хочу, чтобы nginx служил моим дросселем для моего API.

Мой конфигурационный файл содержит хорошо цитированный пример limit_req_zone:

limit_req_zone $binary_remote_addr zone=limit:2m rate=10r/m;

вместе с моей директивой location, содержащей ожидаемый limit_req zone=limit nodelay;

Мне бы хотелось, чтобы nginx прикреплял заголовки к ответному сообщению для атрибутов X-RateLimit-Remaining и X-RateLimit-Reset. В основном, nginx использует активный счетчик rate=10r/m для заполнения X-RateLimit-Remaining и таймфрейма того же значения rate=10r/m, чтобы заполнить X-RateLimit-Reset, сколько секунд осталось до обновления.

http {
    limit_req_zone $binary_remote_addr zone=login:10m rate=2r/s;
    limit_req_status 429;
    limit_conn_status 429;

    server {
        listen       80;
        server_name  [removed];

        location / {
            limit_req zone=limit nodelay;

            proxy_pass http://reverse-proxy-example;
            add_header  X-RateLimit-Remaining [nginx variable?];
            add_header  X-RateLimit-Reset [nginx variable?]
        }
}

Мысли? Возможное? Хотелось бы избежать удара приложения, чтобы получить эти цифры.

Ответ 1

Я бы сказал, что это невозможно с исходной версией nginx.

Вы можете найти документацию для директивы limit_req через http://nginx.org/r/limit_req, которая перенаправляет на http://nginx.org/docs/http/ngx_http_limit_req_module.html#limit_req, что убедительно показывает, что в модуле нет никаких известных переменных внутри него.

Взгляд на http://ngx.su/src/http/modules/ngx_http_limit_req_module.c подтверждает гипотезу.

Другой вариант - взглянуть на http://nginx.org/docs/varindex.html, в котором перечислены все переменные - поиск limit приведет вас только к $limit_rate, который является не связанной переменной.


Постскриптум Учтите, что limit_req выполняется методом утечки.

Не вдаваясь в подробности или придумывая что-либо (статья в Википедии огромна!), Я бы предположил, что представление этой информации конечному пользователю непротиворечивым и действенным образом может быть не совсем тривиальным.

Ответ 2

Packngo из Packet имеет функцию, которая может быть подходящей для того, что вам нужно делать.

Пример из пакета:

func (r *Response) populateRate() {
    // parse the rate limit headers and populate Response.Rate
    if limit := r.Header.Get(headerRateLimit); limit != "" {
        r.Rate.RequestLimit, _ = strconv.Atoi(limit)
    }
    if remaining := r.Header.Get(headerRateRemaining); remaining != "" {
        r.Rate.RequestsRemaining, _ = strconv.Atoi(remaining)
    }
    if reset := r.Header.Get(headerRateReset); reset != "" {
        if v, _ := strconv.ParseInt(reset, 10, 64); v != 0 {
            r.Rate.Reset = Timestamp{time.Unix(v, 0)}
        }
    }
}