一 try_files、content阶段、outfilter再探
① 哪些人适合阅读
适合: 拿nginx作为'静态服务器'网站'前端'人员必备,后端程序员可以'选择性的忽略'
备注: 该篇一个'阶段性'的总结,后续'不再'探讨该部分
补充: 按照'try_files'、'content'阶段的'模块指令'的'执行顺序'讲解
强调: 本文'不具有实际意义',只是试图从'应用层现象'来解读运行机制
① 相关博客系列
备注:学习要有一个'过程',不可能'一蹴而就',下面的博客记录了我的'成长史',某一个时刻就'豁然开朗'
root、alias、index、try_files关系指令再探
precontent阶段的模块学习 核心try_files指令
content阶段index和autoindex模块学习
content阶段static模块学习
filter模块处理
章亦春大神的nginx权威参考
③ content阶段涉及模块指令处理顺序
1) 本次'只探讨'try-files、content阶段,附加'filter'系列模块
2) content 阶段是'所有请求处理阶段中'最为'重要'的一个
特点: 因为运行在'这个阶段'配置指令一般都肩负着生成"内容(content)"并输出'HTTP 响应'的使命
强调: 当存在"content handler 内容处理程序"的指令时,'静态资源服务模块'并'不会'起作用
3) 绝大多数 'nginx 模块'在向 'content 阶段' 主动'注册配置指令'时
重点: 本质上是在'当前的 location 配置块'中'注册'所谓的"内容处理程序(content handler)"
常见: ngx_echo模块 ["echo指令"]、ngx_proxy ["proxy_pass"]
强调:
[1]、每一个 location 只能有一个"内容处理程序"
[2]、当在 location 中同时'使用多个模块'的 content 阶段指令时
[3]、只有'其中一个模块'能成功注册"内容处理程序"
4) 如果location中'没有'使用在 content 阶段'注册的'模块指令,也即没有'content handler'
[1]、处理权便'自动'落到了在 content 阶段"垫底"的那 '3个'静态资源服务模块
[2]、首先运行的 'ngx_index' 和 'ngx_autoindex' 模块
特点: 如果'当前请求的uri'是'以 / 结尾',就会使用对应'index'和'autoindex'指令
[3]、否则直接'弃权',将处理权转给了最后运行的 'ngx_static' 模块
特点: ngx_static 模块根据 '(root|alias) 指令'将'请求$uri' 映射为'文件系统'路径
备注: 这个模块主要实现'服务静态文件'的功能,也是nginx作为'web服务器'的核心
[4]、在确认'磁盘中'文件'存在'后,将它们的内容分别作为响应体输出,并自动设置'相应'响应头
备注: 如果'文件不存在',则返回'404',这才是'资源不存在'
5) 有的'模块'指令是'默认提供的',有的模块'没有指定',则'跳过'这个模块
备注:有些指令作用'对应地方'也能改变'11个阶段'
6) nginx '变量'则经常扮演着在'指令间'乃至'模块间'传递'小份数据'的角色
7) ngx_index、ngx_autoindex、ngx_static模块执行'顺序'和'处理特点'对比:
[1]、ngx_index 和 ngx_autoindex 模块都'只会'作用于那些$uri以'/结尾'的请求
[2]、对于'不以/结尾的请求'则会直接'忽略',同时把处理权移交给'ngx_static 模块'
[3]、而'ngx_static 模块'则刚好相反,直接'忽略'那些 $uri 以 '/ 结尾'的请求
1、'真正'把相应的'内容(正常|异常)'发送出去,还是得靠这个 'ngx_static 模块'来完成
2、所作的操作:即把'该文件的内容'作为响应体数据输出,并设置相应的'响应头'
④ try_files指令再探
知识铺垫
1)precontent'阶段':
特点: 这个阶段'专门'用于实现标准配置指令'try_files'的功能,'不'支持nginx模块注册处理程序
默认: '没有'指定'try_files',所以'precontent'阶段默认'不存在'
2) 语法: try_files file1 file2 ... '(uri|=code)'
本文: 对'try_files'各种行为的探究
备注: 支持'@location'这种'uri'
补充: 这里的'file1 ,file(n-1)'等指的是'资源对象(file|directory)'
最佳实践: try_files $uri $uri/ @wzj;
3) 细节点:'try_files'通过'alias|root'、'$uri'、'location'来判断文件系统对象是否存在
4) 探究案例:
[1]、文件资源'存在'
[2]、文件'不'存在,'目录资源'存在
[3]、前'N-1'个都不存在,'uri|=code'进行匹配
备注: 读者应该'注意'各个案例的'前提条件[上下文]'
观察: 'debug日志'输出,并'分析'
案例1:try_files file '文件'存在时,使用'content handler'和'默认content'行为'对比'实验
+++++++++++++++++++++ "分割线" +++++++++++++++++++++
案例2: try_files file '目录资源对象'存在时
备注: 使用'content handler'和'默认content'行为'对比'实验
++++++++++++++++ "分析过程" ++++++++++++++++
1) nginx 在 try-files 阶段发现'第一个参数 /wzj' 对应的'文件 file'不存在
2) 就会转向检查'第二个参数 /wzj/'对应的'文件系统对象'
3) 由于'此目录'存在,并且'$uri'不是以'/'结尾的
细节: 此时nginx就会把当前请求'uri 改写'为第'二个参数的值(不带末尾/)',即$uri为'/wzj'
注意: try_files '原始'参数值是 /wzj/,但 try_files 会自动'去除末尾'的'斜杠/'字符
4) 由于是一个'目录'资源,nginx会进行'301重定向',并返回'Location: $uri/'
过程:此时$uri不是以'/'结尾,所以'index、autoindex'指令对应的模块不起作用,ngx_static处理
强调:
[1]、实际'try_files 非internal命中',还是会向下'处理','index、autoindex'被忽略
[2]、ngx_static会不是以'/'结尾的'$uri'映射的'文件'或'目录'做不同处理
备注: 理解上可以认为'约等于' 'rewrite ^ $uri/ permanent;'这种'相对'重定向
5) 接着'基于新的url',从客户端重新发起'重定向'请求
6) 在'try_files'由于'第二个参数 /wzj/'匹配判断是'目录',并且$uri是以'/'结尾
7) 此时转交到'ngx_index'模块,由于'此时映射的系统文件不存在',继续'ngx_autoindex'模块
8) 由于上述处理'/'结尾的'$uri'的两个模块没作用,'ngx_static'模块又处理不了以'/'结尾$uri
9) 此时返回'默认'内置的'403'的页面
说明: 下面的是'重定向'请求的'error.log'日志
备注: 同时给出了'$uri以/'结尾,并且'try_files directory'匹配的场景
对比实验: 基于'案例2',前提'条件不变',修改'相对重定向'的策略,观察结果
双层nginx 转发下的 try_files 指令 301 返回错误的 location 地址 try_files导致301
对比实验: 基于'案例2',前提'条件不变',使用'content handler'
强调:
1) 即使是'try_files $uri/'判断'目录资源存在',也会继续进行'content'阶段的处理
2) 所不同的是经过模块注册的'content handler',还是'nginx内置默认的content'
对比实验: 基于'案例2',前提'条件不变',基于'Location 301'使用'exact location'
案例3: 最后一个'uri'起作用
备注:
1) '普通uri' --> '$args'会丢失 --> 'rewrite ^ /java? last'
2) '命名location' --> '$args'不会丢失 --> 'rewrite ^ /java last'
1) try_files 指令本质上只是'有条件'地改写当前'请求的 URI'
2) 这里说的"条件"其实就是文件系统上的'对象(file|directory)是否存在'
3) 当"条件"都不满足时,它就会无条件地发起一个指定的"内部跳转"
备注: 除了无条件地发起'内部跳转'之外, try_files指令还支持直接返回指定状态码'HTTP 错误页'
案例4: 最后一个'=code'起作用,观察'add_header'行为
说明: 从语义上来说,一般使用'404'返回指定状态码的 'HTTP 错误页'
思考: try_files可以指定'哪些'状态码?
备注: 自己尝试过'401'、'301(没有Location)'、使用'20(0|6)'不报错但'阻塞'、'204'是ok
遗留: 如果指定'error_page' 相同'状态码'是否能补获? --> "会"
⑤ index指令再探
思考1: 什么场景会触发'index'指令的执行? --> 假定在一个'location'内
前提: 没有其它模块注册'content handler',并且'$request_uri'以'/'结尾
[1]、'$request_uri'中以'/'结尾,但'没有'指定'try_files'
补充: 'try_files directory'映射系统资源'存在',虽然会改变'$uri',但是会去掉末尾的'/'
强调: 上述是'触发 index'的充分不必要条件,并不意味着'index ...'能命中,只是'有机会'执行
附加: ngx_index 和 ngx_autoindex 模块都只会作用于那些 '$request_uri以/结尾'的请求
思考2: index指令是'如何执行'的?
[1]、依次判定'指定的首页文件'是否存在? --> 基于'(root|alias)'判定
[2]、如果全都'不存在'则进行'ngx_autoindex'模块,要不返回'文件列表',要么返回'403'
[3]、如果存在'指定的首页文件',则基于该'$uri$index_value'发起'internal'内部跳转
备注: 此时index 后续的'value'不再执行,并且'该次内部请求'的'后续阶段'也不再执行
问题1: 为什么我配置的'index'首页却不生效?
原因:
1) 由于'location'优先级原因,进不到之前的'location'中导致异常
2) index 指定的'首页'
场景: 'ngx_index 模块'主要用于在'文件系统目录中'自动查找'指定的首页'文件
思考: 如何才能真正'设置首页'与我们的'预期相符'呢?
案例:
1)案例1:'index .. 匹配不上',观察行为 --> 才有可能轮到'autoindex'指令执行
2)案例2:'index .. 匹配上',只使用一个'location'观察行为
3)案例3:'index .. 匹配上','定义新的 location',观察匹配行为
merge_slashes
1) 'try_files directory[/kafka/]' 改变了'$uri',同时导致301 'Location $uri/'
2) 继续发起请求'/kafka/'进行'index index.html'匹配,'文件'存在
3) index改变'$uri'为'/kafka/index.html',此时不以'/'结尾,autoindex即使配置也无法处理
4) 最后交给'ngx_static'处理
与'案例1'的对比实验: 由于'location的'优先级,导致非预期的'首页'
与'案例1'的对比实验: index 配置的值以'/'结尾,同时'autonindex on'开启观察
1) 第一次'index /wzj/' 查找系统资源为'目录'
强调: 只有'index file'匹配,才会改变'$uri'
2) 导致'$uri'变为'/kafka/wzj/',继续进行'internal'重定向行为
官方: 只有'index (file|dir)'不存在,才会执行'autoindex',index'优先级'高
大白话: 只要'index (file|dir)'匹配上,永远不会执行'autoindex'
3) 通过'add_header或error.log'观察
说明: 'index dir'场景
与上述的'对比'实验: 配置文件'不变',改变'前提条件',请求url'不变'
说明: 注意'autoindex on'执行的'条件',是一个'备胎'
版权归原作者 wzj_110 所有, 如有侵权,请联系我们删除。