• nginx try_files流程解析


    前端部署单页应用时在nginx上经常用到try_files指令,而对于try_files并不知道其所以然,所以花时间整理总结如下。

    Syntax: try_files file … uri;
    try_files file … =code;
    Default: —
    Context: server, location

    根据root和alias指令提供的值按照try_files指令值的顺序查找对应文件是否存在。可以通过以斜杠结(/)尾的文件名让try_files查找文件夹是否存在(例如:“$uri/”)。try_files指令提供的file都不存在那么就会发起内部重定向到uri。如果可以找到file,以找到的第一个file作为条件继续处理当前请求。

    上面的描述没有错,但是不够具体,刚看这个描述我有如下问题:

    1. 对于file和uri,try_files的处理有什么不同?
    2. try_files的处理流程在nginx中具体是什么样的?
    3. 查找到文件和文件之后呢?
    4. 什么是内部重定向?

    准备工作

    1. 开启nginx的debug模式
    • 确保 nginx -V 输出有 configure arguments: --with-debug。如果没有需要重新编译安装ngxin,具体方法借助搜索引擎吧。

    • 在http模块下添加配置:

        http {
          # 设置错误日志地址和日志级别为debug
          error_log path/to/log/file debug;
        }
      
      • 1
      • 2
      • 3
      • 4
    1. 准备验证环境
    • 准备网站根目录 /path/to/www/
    • 添加测试nginx服务:
      server {
        listen 8080;
        root /path/to/www/;
        location / {
          try_files /helloworld.html /hello/ /internalRedirect;
        }
      
        location /internalRedirect {
          return 200 "internalRedirect";
        }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
    1. 准备知识
      nginx 配置文件执行是分为11个阶段按照顺序执行的,try_files流程涉及到的阶段有find-config、try_files和content这三个阶段,server-rewrite、rewrite、post-write等剩余阶段此处省略。

      find-config阶段主要根据请求的uri在nginx文件中寻找匹配的location块。

      try_files阶段主要执行try_files指令。

      content阶段上面的nginx服务只涉及到默认的模块,nginx_index、nginx_autoindex和nginx_static。

    try_files指令解析

    1. 当请求匹配中 location / 时,try_files会去找文件 /path/to/www/helloworld.html没找到会继续找/path/to/www/hello文件夹,都没找到,最后会内部重定向到 /internalRedirect。

      curl http://localhost:8080/
      
      • 1

      返回:

      internalRedirect
      
      • 1

      截取部分debug日志文件。

      [debug] 17945#0: *2 trying to use file: "/helloworld.html" "/path/to/www/helloworld.html"
      [debug] 17945#0: *2 trying to use dir: "/hello" "/path/to/www/hello"
      [debug] 17945#0: *2 trying to use file: "/internalRedirect" "/path/to/www/internalRedirect"
      [debug] 17945#0: *2 internal redirect: "/internalRedirect?"
      [debug] 17945#0: *2 rewrite phase: 1
      [debug] 17945#0: *2 test location: "/"
      [debug] 17945#0: *2 test location: "internalRedirect"
      [debug] 17945#0: *2 using configuration "/internalRedirect"
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8

      nginx执行顺序是先执行findConfig匹配和$uri合适location块配置,才会执行try_files指令,当try_files使用内部重定向的时候,请求的处理流程会被回退到findConfig阶段重新使用/internalRedirect重新匹配location。这个重定向和外部重定向http的301不一样,它并不会引起浏览器地址栏的url的修改,所以被称为内部重定向

    2. 当找到 /helloworld 之后try_files指令会重写 u r i 的 值 , 当 执 行 到 c o n t e n t 阶 段 后 会 依 据 新 的 uri的值,当执行到content阶段后会依据新的 uricontenturi值获取对应的静态文件。

    • 在/path/to/www/文件夹下添加helloworld.html文件,其内容是hello world。

    • 在ngxin配置中添加
      add_header header_uri $uri;

      curl -i http://localhost:8080/  # -i 会展示响应头
      
      • 1

      返回:

      HTTP/1.1 200 OK
      ...
      header_uri: /helloworld.html
      
      hello world
      
      • 1
      • 2
      • 3
      • 4
      • 5

      截取部分log文件日志:

      [debug] 18875#0: *1 trying to use file: "/helloworld.html" "/path/to/www/helloworld.html"
      [debug] 18875#0: *1 try file uri: "/helloworld.html"
      ...
      [debug] 18875#0: *1 http filename: "/path/to/www/helloworld.html"
      
      • 1
      • 2
      • 3
      • 4
    1. 当文件夹hello存在,try_file会将$uri修改为 /hello 接着给content阶段的模块处理。
    • 删除上一步骤的helloworld.html文件。

      curl -i http://localhost:8080/  # -i 会展示响应头
      
      • 1

      返回:

      HTTP/1.1 301 Moved Permanently
      ...
      header_uri: /hello
      
      
      301 Moved Permanently
      
      

      301 Moved Permanently


      nginx/1.23.0
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11

      截取部分log文件日志:

      [debug] 18875#0: *2 trying to use file: "/helloworld.html" "/Users/zhou/nginx_web/helloworld.html"
      [debug] 18875#0: *2 trying to use dir: "/hello" "/Users/zhou/nginx_web/hello"
      [debug] 18875#0: *2 try file uri: "/hello"
      [debug] 18875#0: *2 http filename: "/Users/zhou/nginx_web/hello"
      [debug] 18875#0: *2 http static fd: -1
      [debug] 18875#0: *2 http dir
      [debug] 18875#0: *2 http finalize request: 301, "/hello?" a:1, c:1
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7

      为什么try_files寻找文件夹的时候需要把指令值/hello/改成/hello?我理解末尾的斜杠只是表示try_files这个名字是一个文件夹名,所以找的时候把末尾的斜杠去掉了,如果想要$uri被赋值的时候带上末尾的斜杠可以 try_files /helloworld.html /hello// /internalRedirect,可以给他多加一个斜杠。

    参考

    agentzh 的 Nginx 教程(版本 2020.03.19)

    Nginx文档try_files指令

  • 相关阅读:
    机器学习 - 机器学习理论基础
    干货分享 | MindSpore21天实战营手记(四):基于YOLOV3-DarkNet50的篮球检测模型
    信息系统项目管理师 第四版 第15章 项目风险管理
    Sql注入的基础
    【AI视野·今日NLP 自然语言处理论文速览 第四十八期】Thu, 5 Oct 2023
    【前端源码解析】数据响应式原理
    Flutter实战-自定义键盘(三)
    每天一个数据分析题(三百九十六)- 回归分析
    RT-Thread 中断管理(学习一)
    SSRF漏洞
  • 原文地址:https://blog.csdn.net/letterTiger/article/details/127941596