Nginx If 语句在 location 之前执行? [英] Nginx If statement executed before location?

查看:92
本文介绍了Nginx If 语句在 location 之前执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很困惑为什么 nginx 会执行我的 If 语句before"位置声明.更准确地说,为什么nginx不执行return语句然后停止处理?

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

 服务器 {听 80 default_server;听 [::]:80 default_server;服务器名称  _;根目录/usr/share/nginx/html;index index.html index.htm index.php;位置/xyz {返回 200 '你好世界';}如果 ($http_x_forwarded_host != "www.acme.com") {返回 301 https://www.acme.com$uri;}}

解决方案

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

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

 if ($http_x_forwarded_host != "www.acme.com") {# 仅当 URI 不以/xyz"开头时才进行重定向重写 ^(?!/xyz) https://www.acme.com$uri 永久;}位置/xyz {返回 200 '你好世界';}

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

 if ($http_x_forwarded_host != "www.acme.com") {# 以防您以后需要原始URI,您可以保存它的值# 设置 $original_uri $uri;# 仅当 URI 不以/xyz"开头时才处理具有特殊位置的请求重写 ^(?!/xyz)/special;}位置/xyz {返回 200 '你好世界';}位置/特殊{内部的;... # 此处的任何自定义处理,例如 'return 403;'}

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

I'm confused why nginx is executing my If statement "before" the location statement. More precise, why is nginx not executing the return statement and then stops processing?

I would expect if I open /xyz to get a 200 with "hello world" even if $http_x_forwarded_host is not www.acme.com because the if statement is located down the location statement. But nginx just ignor the location statement and ran into the if clause. Any ideas? I tried break; with no luck.

    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;
        }


    }

解决方案

You are right, all directives from the ngx_http_rewrite_module are executed before the location selection mechanism took its place. Using the break directive means breaking the execution of those directives from the rewrite module and immediately force the request execution according to the best matching location. This happened because although nginx configuration in general is declarative, rewrite module evaluates its instructions imperatively. This is always a source of confusion for every nginx novice. You can read more about the rewrite module internal implementation here.

Being that said, you can't implement that sort of behavior with your configuration. It doesn't mean you can't achieve what you want at all, one of possible solutions is to use the regex negative lookahead feature:

    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';
    }

If you want to do some complex request processing instead of redirection, you can use an internal location:

    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;'
    }

It should be obvious that for such a locations you should choose an URI prefix than can't interfere with your existing site in any ways.

这篇关于Nginx If 语句在 location 之前执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆