使用NGINX进行条件重写或try_files?

时间:2015-08-03 07:37:53

标签: nginx rewrite

我在设置条件重写方面遇到了麻烦,而且我一直在尝试使用if指令(尽管所有消息来源都指出了它"'s" evil&#34 ;)使用-f开关检查是否存在文件,但它无法正常工作。我相信问题/案例最好用例子来解释,所以这里有:

目录结构

workspace/
  myapp/
    webroot/
      index.php
      assets/
        baz.js
        hello/
          foo.js
    modules/
      hello/
        assets/
          foo.js
          bar.js

预期结果

/                     =>  /workspace/myapp/webroot/index.php
/assets/hello/foo.js  =>  /workspace/myapp/webroot/assets/hello/foo.js
/assets/hello/bar.js  =>  /workspace/myapp/modules/hello/assets/foo.js
/assets/baz.js        =>  /workspace/myapp/webroot/assets/baz.js

总结:

  • foo.js仅出现在modules/hello/assets文件夹中,并从那里发送。
  • bar.js出现在webroot/assets/hellomodules/hello/assets中,并从webroot发送。 (它隐藏/覆盖modules
  • 中的文件
  • baz.js仅出现在webroot/assets中,并从那里发送。

现在不能正常工作的部分是:

location /assets/ {
    if (-f $uri) {
        break;
    }
    root     /workspace/myapp/modules;
    rewrite  ^/assets/([^/]+)/(.*)$ /$1/assets/$2 break;
}

if指令似乎没有任何影响 - bar.js文件来自modules而不是webroot

我应该使用if吗?

我有什么办法可以用try_files来解决这个问题吗?我似乎无法理解这与rewrite一起工作的方式,而这似乎无法解决。

请不要建议使用部署脚本或其他东西重新组织资产 - 出于各种其他原因,它不是一种选择。

之前我曾在Apache中使用过这种模式,NGINX在大多数方面似乎更有能力,所以我确定这一定是可能的吗?

一个绝对的要求是,我 能够覆盖modules/hello/assets/foo.js webroot/assets/hello/foo.js - 来自{{{然而,1}}是一项要求。

1 个答案:

答案 0 :(得分:2)

答案分为两部分:第一部分解释了为什么您的配置不起作用,第二部分提供了如何解决问题的示例。如果您只对解决方案感兴趣,请直接进入第二部分。

问题

首先,请注意root块中location指令的位置并不重要。如果将它放在location的顶部或底部并不重要,它会影响整个location。另外,请记住,break行末尾的rewrite告诉Nginx保持在当前位置,即使URI已成功重写。

话虽如此,让我们看一下您的配置,看看Expected results的每个请求是如何处理的,以及为什么没有按预期工作。

我们假设您的配置中没有其他合适的location具有更高的优先级。由于Expected results的每个请求都以/assets开头,因此所有请求都将根据您location中提供的规则进行处理。所以:

  1. /assets/hello/foo.js
  2. root设置为/workspace/myapp/modulesif指令将被评估为false,因为/assets/hello/foo.js不存在,因此break将不会被执行。最后,最后rewrite会将请求的URI从/assets/hello/foo.js更改为/hello/assets/foo.js,而后面的break会告诉Nginx保持在当前location范围内。因此,/workspace/myapp/modules/hello/assets/foo.js将被提供。

    1. /assets/hello/bar.js
    2. 此请求的处理方式与上一个请求完全相同,因此/workspace/myapp/modules/hello/assets/bar.js将会提供。{/ p>

      1. /assets/baz.js
      2. 同样,root设置为/workspace/myapp/modulesif评估为false。但是这次最终rewrite不会更改URI,因为请求与正则表达式不匹配。因此,Nginx将尝试提供/workspace/myapp/modules/assets/baz.js,因为不存在此类文件,将返回404。

        正如您所看到的,您的配置可能无法正常工作,原因如下:

        • if始终被评估为false,因为您尝试检查URI而不是文件;
        • 请求保留在该位置内,因为您告诉它在break行中rewrite留在那里;
        • root始终在此位置设置为/workspace/myapp/modules,因此无法从其他任何位置投放任何文件。

        解决方案

        1. 最简单的解决方案是使用try_files

          root /workspace/myapp/webroot;
          
          location /assets/ {
              try_files $uri @modules;
          }
          
          location @modules {
              root     /workspace/myapp/modules;
              rewrite  ^/assets/([^/]+)/(.*)$ /$1/assets/$2 break;
          }
          

          此配置告诉Nginx首先在webroot文件夹中查找文件,如果没有找到,则转到另一个位置的modules文件夹。这种方法被认为是最可取的。

        2. 另一方面,使用if可以让您在一个位置解决问题:

          location /assets/ {
              root /workspace/myapp; # The parent folder
          
              if (-f $document_root/webroot/$uri) {
                  rewrite ^(.*)$ /webroot/$1 break;
              }
          
              rewrite  ^/assets/([^/]+)/(.*)$ /modules/$1/assets/$2 break;
          }
          

          但是,建议不要使用此方法过时。