在 nginx 中共享位置配置

Sharing location configuration in nginx

我无法决定问题的最佳名称。

服务器将所有 API 请求反向代理到后端服务。

在全局 nginx 配置中 /etc/nginx/nginx.conf 我设置了允许的最大主体大小的规则,就像这样 client_max_body_size 50k;

然后,在单独的服务器配置中 /etc/nginx/conf.d/example.com 我有以下配置(简化):

server {
    listen 80;
    listen [::]:80;
    
    server_name api.example.com www.api.example.com
    
    location ~* /file/upload {
        client_max_body_size 100M;

        # crashes without this line
        proxy_pass http://localhost:90;
        #proxy_pass http://localhost:90/file/upload; # also works
    }
        
    location / {
        # does not work
        #location ~* /file/upload {
        #   client_max_body_size 100M;
        #}
        
        proxy_pass http://localhost:90;
    }
}

我正在尝试覆盖文件上传端点的最大正文大小。看到位置 /file/upload 有 1 个 proxy_pass,位置 / 有另一个 proxy_pass,指向同一个内部服务。

问题 1。如果我从位置 /file/upload 中删除 proxy_pass,则服务器返回错误。 (chrome 调试器中没有状态代码)。为什么会这样?不应将请求进一步传播到位置 /

问题 2。为什么不能像上面示例中的注释部分那样在 / 位置内定义带有正文大小覆盖的子位置?如果我这样设置,则会返回413错误代码,提示client_max_body_size 规则被忽略..

问题 3。最后,是否可以在请求到达 /file/upload 位置后告诉 nginx - 应用 / 部分中的所有规则?我想这个问题的一个解决方案是将通用配置移动到单独的文件中,然后在两个部分中导入它。我在想是否有不需要创建新文件的解决方案?

这里是我所说的可重复使用的配置:

location / {
    #.s. kill cache. use in dev
    sendfile off;

    # kill cache
    add_header Last-Modified $date_gmt;
    add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0';
    if_modified_since off;
    expires off;
    etag off;
    
    # don't cache it
    proxy_no_cache 1;

    # even if cached, don't try to use it
    proxy_cache_bypass 1; 
    
    proxy_pass http://localhost:90;
    
    client_max_body_size 100M;
    
    proxy_http_version 1.1;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $http_host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_pass_request_headers on;
}

这不是最终版本。如果我必须将这段代码复制到 2 个部分,这将不是非常友好的方法。因此,很高兴听到一些关于如何以最友好的方式完成我试图完成的事情的生活窍门,并获得对观察到的行为的一些解释。

回答 1

If I remove the proxy_pass from the location /file/upload then error is returned by the server. (no status code in chrome debugger). Why is this happening?

每个位置都有一个 so-called 内容处理程序 。如果您没有通过 proxy_passfastcgi_passuwsgi_pass 等)指令明确指定内容处理程序,nginx 将尝试在本地处理请求。

Shouldn't request be propagated further to location /?

当然不是。是什么让您认为应该这样做?

回答2

Why is it not possible to define the sublocation with body size override inside the / location as in commented section in example above? If I set it like this, then 413 error code is returned, which hints that the client_max_body_size rule is ignored..

我希望您会得到与第一种情况相同的错误,因为您的嵌套位置没有通过 proxy_pass 指令明确指定的内容处理程序。但是以下配置值得一试:

location / {
    # all the common configuration
    location /file/upload {
        client_max_body_size 100M;
        proxy_pass http://localhost:90;
    }
    proxy_pass http://localhost:90;
}

回答 3

Finally, is it possible to tell nginx, after the request hits the /file/upload location - to apply all the rules from the / section?

否,除非您通过 include 指令在两个位置使用单独的文件。但是,您可以尝试将所有与上游相关的设置指令向上移动一级到 server 上下文:

server {
    ...
    # all the common configuration
    location / {
        proxy_pass http://localhost:90;
    }
    location /file/upload {
        client_max_body_size 100M;
        proxy_pass http://localhost:90;
    }
}

请注意,当且仅当当前级别上没有定义这些指令时,某些指令(例如 add_headerproxy_set_header)是从以前的配置级别继承的。

经常可以通过以下方式使用 map 块实现不同位置的动态设置:

map $uri $max_body_size {
    ~^/file/upload    100M;
    default           50k;
}
server {
    location / {
        ...
        client_max_body_size $max_body_size;
        ...
    }
}

不幸的是,并非每个 nginx 指令都接受变量作为其参数。通常当 nginx 文档没有明确说明某些指令可以接受变量时,就意味着它不能接受变量,而 client_max_body_size 正是这种指令,所以上面的配置将不起作用。