Nginx returns 限速时 CORS 错误而不是 429

Nginx returns CORS error instead of 429 when rate limiting

我一直在尝试对我异步访问的某些 api 端点进行速率限制,在速率限制之前请求 return 200 ok,但是当达到限制而不是 return我的 api 端点出现 429 错误,在浏览器中返回 CORS 错误,我 这可能是由于某些 headers,但我试过了,但我仍然得到相同的 cors 错误。

在下面分享我简陋的 nginx 配置,在这个例子中我想在端点达到速率限制时得到 429 api.domain.com/custom/url

http {
    limit_req_zone $binary_remote_addr zone=mylimit:10m rate=5r/m;

    server {
        listen 80;
        server_name domain.com api.domain.com;

        location .../my-acme-challenge/ {
            root .../my-certbot;
        }

        location / {
            return 301 https://$server_name$request_uri;
        }
    }

    server {
        listen 443 ssl;
        server_name api.domain.com;

        .../mychain.pem;
        .../myprivkey.pem;
        include .../my-options-ssl-nginx.conf;
        ssl_dhparam .../my-ssl-dhparams.pem;


        Relevant Piece !!!!!!
        location /custom/url {
            add_header Access-Control-Allow-Credentials 'true' always;
            add_header Access-Control-Allow-Origin '*' always;
            limit_req zone=mylimit burst=5 nodelay;
            limit_req_log_level error;
            limit_req_status 429;
            proxy_pass http://myip:myport/custom/url;
        }

        location / {
            proxy_pass http://myip:myport;
        }
    }

    ...

}

知道会发生什么吗?尽量简化我的配置。

我的网络截图:

我的 nginx 日志:

[error] 9#9: *51 limiting requests, excess: 5.697 by zone "mylimit", client: myip, server: api.example.com, request: "OPTIONS /custom/url HTTP/1.1", host: "api.example.com", referrer: "https://example.com/"

myip - - [23/Nov/2021:01:10:32 +0000] "OPTIONS /custom/url HTTP/1.1" 429 571 "https://example.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36"

更新:

奇怪的是,当我从网络复制 curl 请求时(右键单击 > 复制 > 复制为 curl)我得到这个 html 页面,它看起来是一个 429,但我应该得到这个当我遇到不在 curl 中的异步请求时,浏览器出现错误。

location 块之外添加您的 headers 应确保它们也包含在速率限制响应中。

server {
  add_header Access-Control-Allow-Origin * always;

  location / {
    add_header Access-Control-Allow-Origin * always;
    ...
  }

  ...
}

如果其他人遇到同样的情况,则问题实际上是多种因素的组合:

  1. 需要特别处理预检请求,否则会出现与之相关的错误,我遵循了 this answer:
  2. 的方法
if ($request_method = 'OPTIONS') {
    add_header 'Access-Control-Allow-Origin' 'https://example.com' always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    add_header 'Access-Control-Allow-Methods' 'GET, HEAD, OPTIONS, POST, PUT, DELETE' always;
    add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, contentType, Content-Type, Accept, Authorization, Pragma' always;
    add_header 'Access-Control-Max-Age' 1728000;
    add_header 'Content-Type' 'text/plain charset=UTF-8';
    add_header 'Content-Length' 0;
    return 204;
}
  1. 我发现我的上游服务器和 nginx 设置的 headers 之间存在冲突,所以我从上游删除了所有 headers,只保留了 nginx 的 headers,现在添加我的headers 到 server {} 级别的所有请求(注意 always 关键字,这是将 headers 添加到错误响应的关键)即:
    add_header 'Access-Control-Allow-Origin' 'https://example.com' always;
    add_header 'Access-Control-Allow-Credentials' 'true' always;
    add_header 'Access-Control-Allow-Methods' 'GET, HEAD, OPTIONS, POST, PUT, DELETE' always;
    add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, contentType, Content-Type, Accept, Authorization, Pragma' always;
  1. 由于来自 nginx 的响应不是 JSON,我不得不向我的请求处理程序添加一些手动验证,以在尝试解析任何异步请求的响应之前验证错误代码。