30

我实际上有点惊讶,经过几个小时的谷歌搜索后我找不到任何东西,但问题如下:

我希望 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-RemainingX-RateLimit-Reset属性的响应消息中。rate=10r/m基本上让nginx使用填充的活动计数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?]
        }
}

想法?可能的?希望避免点击应用程序来获取这些数字。

4

3 回答 3

2

我会说这对于 nginx 的上游版本是不可能的。

您可以通过http://nginx.org/r/limit_req找到该limit_req指令的文档,该文档重定向到http://nginx.org/docs/http/ngx_http_limit_req_module.html#limit_req,最终表明该模块没有t 中包含任何已知变量。

查看http://ngx.su/src/http/modules/ngx_http_limit_req_module.c证实了猜想。

另一种选择是查看http://nginx.org/docs/varindex.html,它列出了所有变量 - 查找limit只会让您找到$limit_rate,这是一个不相关的变量。


PS考虑这limit_req是通过漏桶方法完成的。

在不深入细节或编造东西的情况下(维基百科的文章很大!),我猜想以一致且可操作的方式向最终用户呈现这些信息可能并非完全微不足道。

于 2019-08-15T22:39:00.020 回答
0

就像@cnst的回答一样,没有一个合适的变量来保存你想要的值,如果你真的想要这个消息,你可以实现一个lua函数来保存这个消息。nginx 配置是这样的:

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];
        set $x-ratelimit-ramaining 0;
        set $x-ratelimit-reset 0;
        access_by_lua_file your_file_name.lua;

        location / {
            limit_req zone=limit nodelay;

            proxy_pass http://reverse-proxy-example;
            add_header  X-RateLimit-Remaining $x-rate-limit-remaining;
            add_header  X-RateLimit-Reset $x-ratelimit-reset;
        }
}

因此,每个请求都会触发 lua 脚本,您可以更新$x-rate-limit-remaining $x-ratelimit-resetlua 函数中的变量。

于 2019-12-20T10:25:19.117 回答
-4

Packet的Packngo有一个功能可能非常适合您需要做的事情。

来自 packngo 的样本:

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)}
        }
    }
}
于 2017-03-29T03:10:56.780 回答