首页 > 解决方案 > Nginx If语句在位置之前执行?

问题描述

我很困惑为什么 nginx 在 location 语句“之前”执行我的 If 语句。更准确的说,为什么nginx不执行return语句然后停止处理?

即使 $http_x_forwarded_host 不是www.acme.com因为 if 语句位于 location 语句的下方,我希望如果我打开 /xyz 会得到带有“hello world”的 200。但是 nginx 只是忽略了 location 语句,并遇到了 if 子句。有任何想法吗?我试过break;没有运气。

    server {
    listen       80 default_server;
    listen       [::]:80 default_server;
    server_name  _;
    root         /usr/share/nginx/html;
    index   index.html index.htm index.php;
    
        location /xyz {
          return 200 'hello world';

        }

        if ($http_x_forwarded_host != "www.acme.com") {
                return 301 https://www.acme.com$uri;
        }


    }

标签: nginx

解决方案


你是对的,来自 的所有指令都是在位置选择机制取代它之前ngx_http_rewrite_module执行的。使用指令意味着从重写模块中断这些指令的执行,并立即根据最佳匹配位置强制执行请求。发生这种情况是因为尽管 nginx 配置通常是声明性的,但 rewrite 模块命令式地评估其指令。这对于每个 nginx 新手来说总是一个困惑的根源。您可以在此处阅读有关重写模块内部实现的更多信息。break

话虽如此,您无法通过配置实现这种行为。这并不意味着您根本无法实现您想要的,一种可能的解决方案是使用正则表达式负前瞻功能:

    if ($http_x_forwarded_host != "www.acme.com") {
        # do the redirect only if the URI doesn't start with '/xyz'
        rewrite ^(?!/xyz) https://www.acme.com$uri permanent;
    }
    location /xyz {
        return 200 'hello world';
    }

如果你想做一些复杂的请求处理而不是重定向,你可以使用一个internal位置:

    if ($http_x_forwarded_host != "www.acme.com") {
        # in case you will need an original URI later, you can save its value
        # set $original_uri $uri;
        # process the request with the special location only if the URI doesn't start with '/xyz'
        rewrite ^(?!/xyz) /special;
    }
    location /xyz {
        return 200 'hello world';
    }
    location /special {
        internal;
        ... # any custom processing here, for example 'return 403;'
    }

很明显,对于这样的位置,您应该选择一个不会以任何方式干扰您现有站点的 URI 前缀。


推荐阅读