紧跟在 post-access 阶段之后的是 try-files 阶段。这个阶段专门用于实现标准配置指令 try_files 的功能,并不支持 Nginx 模块注册处理程序。由于 try_files 指令在许多 FastCGI 应用的配置中都有用到,所以我们不妨在这里简单介绍一下。

try_files 指令接受两个以上任意数量的参数,每个参数都指定了一个 URI. 这里假设配置了 N 个参数,则 Nginx 会在 try-files 阶段,依次把前 N-1 个参数映射为文件系统上的对象(文件或者目录),然后检查这些对象是否存在。一旦 Nginx 发现某个文件系统对象存在,就会在 try-files 阶段把当前请求的 URI 改写为该对象所对应的参数 URI(但不会包含末尾的斜杠字符,也不会发生 “内部跳转”)。如果前 N-1 个参数所对应的文件系统对象都不存在,try-files 阶段就会立即发起“内部跳转”到最后一个参数(即第 N 个参数)所指定的 URI.

前面在 (六) 和 (七) 中已经看到静态资源服务模块会把当前请求的 URI 映射到文件系统,通过 root配置指令所指定的“文档根目录”进行映射。例如,当“文档根目录”是 /var/www/ 的时候,请求 URI/foo/bar 会被映射为文件 /var/www/foo/bar,而请求 URI /foo/baz/ 则会被映射为目录 /var/www/foo/baz/. 注意这里是如何通过 URI 末尾的斜杠字符是否存在来区分“目录”和“文件”的。我们正在讨论的 try_files配置指令使用同样的规则来完成其各个参数 URI 到文件系统对象的映射。

不妨来看下面这个例子:

    root /var/www/;
 
    location /test {
        try_files /foo /bar/ /baz;
        echo "uri: $uri";
    }
 
    location /foo {
        echo foo;
    }
 
    location /bar/ {
        echo bar;
    }
 
    location /baz {
        echo baz;
    }

这里通过 root 指令把“文档根目录”配置为 /var/www/,如果你系统中的 /var/www/ 路径下存放有重要数据,则可以把它替换为其他任意路径,但此路径对运行 Nginx worker 进程的系统帐号至少有可读权限。我们在location /test 中使用了 try_files 配置指令,并提供了三个参数,/foo/bar/ 和 /baz. 根据前面对try_files 指令的介绍,我们可以知道,它会在 try-files 阶段依次检查前两个参数 /foo 和 /bar/ 所对应的文件系统对象是否存在。

不妨先来做一组实验。假设现在 /var/www/ 路径下是空的,则第一个参数 /foo 映射成的文件/var/www/foo 是不存在的;同样,对于第二个参数 /bar/ 所映射成的目录 /var/www/bar/ 也是不存在的。于是此时 Nginx 会在 try-files 阶段发起到最后一个参数所指定的 URI(即 /baz)的“内部跳转”。实际的请求结果证实了这一点:

    $ curl localhost:8080/test
    baz

显然,该请求最终和 location /baz 绑定在一起,执行了输出 baz 字符串的工作。上例中定义的 location /foo 和 location /bar/ 完全不会参与这里的运行过程,因为对于 try_files 的前 N-1 个参数,Nginx 只会检查文件系统,而不会去执行 URI 与 location 之间的匹配。

对于上面这个请求,Nginx 会产生类似下面这样的“调试日志”:

    $ grep trying logs/error.log
    [debug] 3869#0: *1 trying to use file: "/foo" "/var/www/foo"
    [debug] 3869#0: *1 trying to use dir: "/bar" "/var/www/bar"
    [debug] 3869#0: *1 trying to use file: "/baz" "/var/www/baz"

通过这些信息可以清楚地看到 try-files 阶段发生的事情:Nginx 依次检查了文件 /var/www/foo 和目录/var/www/bar,末了又处理了最后一个参数 /baz. 这里最后一条“调试信息”容易产生误解,会让人误以为 Nginx 也把最后一个参数 /baz 给映射成了文件系统对象进行检查,事实并非如此。当 try_files 指令处理到它的最后一个参数时,总是直接执行“内部跳转”,而不论其对应的文件系统对象是否存在。

接下来再做一组实验:在 /var/www/ 下创建一个名为 foo 的文件,其内容为 hello world(注意你需要有/var/www/ 目录下的写权限):

    $ echo 'hello world' > /var/www/foo

然后再请求 /test 接口:

    $ curl localhost:8080/test
    uri: /foo

这里发生了什么?我们来看,try_files 指令的第一个参数 /foo 可以映射为文件 /var/www/foo,而 Nginx 在try-files 阶段发现此文件确实存在,于是立即把当前请求的 URI 改写为这个参数的值,即 /foo,并且不再继续检查后面的参数,而直接运行后面的请求处理阶段。

上面这个请求在 try-files 阶段所产生的“调试日志”如下:

    $ grep trying logs/error.log
    [debug] 4132#0: *1 trying to use file: "/foo" "/var/www/foo"

显然,在 try-files 阶段,Nginx 确实只检查和处理了 /foo 这一个参数,而后面的参数都被“短路”掉了。

类似地,假设我们删除刚才创建的 /var/www/foo 文件,而在 /var/www/ 下创建一个名为 bar 的子目录:

    $ mkdir /var/www/bar

则请求 /test 的结果也是类似的:

    $ curl localhost:8080/test
    uri: /bar

在这种情况下,Nginx 在 try-files 阶段发现第一个参数 /foo 对应的文件不存在,就会转向检查第二个参数对应的文件系统对象(在这里便是目录 /var/www/bar/)。由于此目录存在,Nginx 就会把当前请求的 URI 改写为第二个参数的值,即 /bar(注意,原始参数值是 /bar/,但 try_files 会自动去除末尾的斜杠字符)。

这一组实验所产生的“调试日志”如下:

    $ grep trying logs/error.log
    [debug] 4223#0: *1 trying to use file: "/foo" "/var/www/foo"
    [debug] 4223#0: *1 trying to use dir: "/bar" "/var/www/bar"

我们看到,try_files 指令在这里只检查和处理了它的前两个参数。

通过前面这几组实验不难看到,try_files 指令本质上只是有条件地改写当前请求的 URI,而这里说的“条件”其实就是文件系统上的对象是否存在。当“条件”都不满足时,它就会无条件地发起一个指定的“内部跳转”。当然,除了无条件地发起“内部跳转”之外,try_files 指令还支持直接返回指定状态码的 HTTP 错误页,例如:

    try_files /foo /bar/ =404;

这行配置是说,当 /foo 和 /bar/ 参数所对应的文件系统对象都不存在时,就直接返回 404 Not Found 错误页。注意这里它是如何使用等号字符前缀来标识 HTTP 状态码的。

Nginx 配置指令的执行顺序(十一)的更多相关文章

  1. Nginx 配置指令的执行顺序(八)

    前面我们详细讨论了 rewrite.access 和 content 这三个最为常见的 Nginx 请求处理阶段,在此过程中,也顺便介绍了运行在这三个阶段的众多 Nginx 模块及其配置指令.同时可以 ...

  2. Nginx 配置指令的执行顺序(五)

    Nginx 的 content 阶段是所有请求处理阶段中最为重要的一个,因为运行在这个阶段的配置指令一般都肩负着生成“内容”(content)并输出 HTTP 响应的使命.正因为其重要性,这个阶段的配 ...

  3. Nginx 配置指令的执行顺序(一)

    大多数 Nginx 新手都会频繁遇到这样一个困惑,那就是当同一个 location 配置块使用了多个 Nginx 模块的配置指令时,这些指令的执行顺序很可能会跟它们的书写顺序大相径庭.于是许多人选择了 ...

  4. Nginx配置指令的执行顺序

    rewrite阶段 rewrite阶段是一个比较早的请求处理阶段,这个阶段的配置指令一般用来对当前请求进行各种修改(比如对URI和URL参数进行改写),或者创建并初始化一系列后续处理阶段可能需要的Ng ...

  5. Nginx 配置指令的执行顺序(十)

    运行在 post-rewrite 阶段之后的是所谓的 preaccess 阶段.该阶段在 access 阶段之前执行,故名preaccess. 标准模块 ngx_limit_req 和 ngx_lim ...

  6. Nginx 配置指令的执行顺序(六)

    前面我们在 (五) 中提到,在一个 location 中使用 content 阶段指令时,通常情况下就是对应的 Nginx 模块注册该 location 中的“内容处理程序”.那么当一个 locati ...

  7. Nginx 配置指令的执行顺序(三)

    如前文所述,除非像 ngx_set_misc 模块那样使用特殊技术,其他模块的配置指令即使是在 rewrite 阶段运行,也不能和 ngx_rewrite 模块的指令混合使用.不妨来看几个这样的例子. ...

  8. Nginx 配置指令的执行顺序(二)

    我们前面已经知道,当 set 指令用在 location 配置块中时,都是在当前请求的 rewrite 阶段运行的.事实上,在此上下文中,ngx_rewrite 模块中的几乎全部指令,都运行在 rew ...

  9. Nginx 配置指令的执行顺序

    在一个 location 中使用 content 阶段指令时,通常情况下就是对应的 Nginx 模块注册该 location 中的“内容处理程序”.那么当一个 location 中未使用任何 cont ...

随机推荐

  1. H5本地存储

    在HTML5中可以把数据长期存储在客户端,使用的对象就是localStorage. localStorage常用方法有setItem.getItem.removeItem.clear. 下面是一个存储 ...

  2. curl fake ip

    curl --header "X-Forwarded-For: 219.137.148.2" "http://www.x.com"

  3. 禁用物料不允许BOM

    应用 Oracle Bill Of   Materiel 层 Level Function 函数名 Funcgtion Name BOM_BOMFDBOM 表单名 Form Name BOMFDBOM ...

  4. QT字体的设置

    摘要: QT4.7.0在移植到开发板上的时候,中文支持是必不可少的,如何让QT支持中文,如何制作QT支持的字体文件,如何使QT UI编辑器中的字号与开发板中的字号一致.作者通过实验进行了一一验证. 介 ...

  5. c++ ifstream ofstream 文件流

    #include <fstream>ofstream //文件写操作 内存写入存储设备 ifstream //文件读操作,存储设备读区到内存中fstream //读写操作,对打开的文件可进 ...

  6. java设计模式--创建模式--工厂方法

    工厂方法定义: 工厂方法 概述 定义一个用于创建对象的接口,让子类决定实例化哪一个类.FactoryMethod使一个类的实例化延迟到其子类. 适用性 .当一个类不知道它所必须创建的对象的类的时候. ...

  7. LeeCode-Merge Sorted Array

    Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. Note:Yo ...

  8. oracle获取某一字段字符串长度

    用length方法 select t.* from tp_area t where substr(t.area_id,0,2)='03' and length(t.area_id)>2

  9. IOS7 UITableView一行滑动删除后 被删除行的下一行的点击事件将被忽略解决办法

    - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSI ...

  10. [Android4.4.3] Nubia Z5S Mokee4.4.3 RC2.0 by syhost

    这个ROM先前在Mokee官网公布过,但一些人測试bug不少,因此已经撤下, 但又有人反馈跟之前RC1.0版的bug差点儿相同, 所以再次在网盘单独公布, 截图以及注意事项见之前的RC1.0的帖子, ...