一 location
server块中的'rewrite'阶段执行完,进入'find_config'阶段,进行'location'匹配
① location
细节点: '$uri[不携带查询参数的path]'与'location'进行匹配
特点: 根据'用户请求的URI'来匹配'location',匹配'success'则执行对应的'configure'配置块
② location中的符号
++++++++++++ '几种符号的理解' ++++++++++++
(1) 第'1'阶段:'前缀(prefix)'匹配 --> 'the longest prefix mactch'
'=': 表示'精准exact'匹配,必须'完全一致才会停止'匹配其它的location
'^~':也是'前缀'匹配,'no regex';但是只有是'最长前缀匹配'时,才会'停止匹配'其它的location
'空':表示一般'prefix前缀'匹配
(2) 第'2'阶段:'正则(regular)'匹配
'~': 区分'大小写'
'~*':不区分大小写
备注: 不能在location 'regular'中使用'!'
(3) '命名@'匹配
应用场景:'error_page'、'try_files'指令、'X-Accel-Redirect'响应头可以使用
关注点:什么是'prefix string'?、什么是'regular expression'? --> "对应哪些修饰符"?
1.location 的匹配'查找'顺序是"先匹配普通,再匹配正则"
'一句话'总结:
1) 正则 location 匹配'让步'普通 location 的严格精确匹配结果
2) 但'覆盖'普通 location 的'最大'前缀匹配结果
nginx会在'启动'过程中,将'server{}内'的所有location'基于前缀'的包含关系,建立一颗'多叉树'
++++++++++++ "假定这些无modifier的前缀location" ++++++++++++
location /test {root html;}
location /res {root html/res;}
location /res/img {root html/res/img;}
location /res/video {root html/res/video;}
location / {root html/res;}
location /resource/js {root html/res;}
location /resource/image {root html/res;}
location /his {root html/res;}
location /his/20 {root html/res;}
location /his/2020 {root html/res;}
location /his/20/02 {root html/res;}
location = /50x.html {}
1)如下'12'个location将会构造出1颗'4层的静态树'
2)其中'子树'中的所有location,都是比'父结节更长'的前缀location
3)在'同一层'的结点中,它们互不相属,但却是'基于字母表'有序的
++++++++++++ "顺序排列问题" ++++++++++++
④ 如何匹配正则表达式location
说明: 遇到'前缀匹配无法覆盖'的url时,可以使用'正则表达式'匹配请求
1)多个正则表达式location之间的'匹配次序'
2) 按照它们在server{}块中'出现'的位置,'依次'匹配,直接使用'最先命中'的location即可
2)注意:当'上方'的正则表达式匹配'范围过大'时,下方的正则表达式location可能永远也'无法命中'
⑤ 正则表达式与前缀location同时出现时
1)= 前缀精确匹配
1)在执行'前缀'匹配时,如果URL与location'完全相等'
2)那么nginx'不会再检索'子树寻找更长的'前缀'匹配,但还会执行'正则'表达式匹配
3)如果你希望'URL完全相等'后,'不必'再匹配正则表达式location,那么可以在location前增加'='号
4)应用场景:如果某些页面'访问频率'非常高,你应该用'='号加快location的'匹配'速度
2) ^~
注意:只有'最长匹配上'携带'^~'符号,才能够'跳过'正则表达式
+++++++++++++ "解读" +++++++++++++
1)虽然这个请求'同时命中了3个'location
2)但'2个前缀'location中
[1]、/redirect1虽然带有'^~'符号,可惜它却'不是最长'的前缀匹配
[2]、而/redirect11虽然是'最长'前缀,但又'不能阻止'正则表达式
3)最终'/redirect1(\d)?'匹配上'url'
⑥ location匹配顺序
++++++++++++ '优先级问题' ++++++++++++
注意:不是按照'nginx.conf'配置文件的'location'先后顺序匹配的
(1) 先匹配所有的'prefix location'
(2) 首先'='前缀精准匹配,匹配成功立即'处理并且停止'location继续匹配
(3) 如果'没有'精准匹配,会进行'^~前缀匹配',^~匹配上也会立即'处理并且停止'location继续匹配
(4) 如果'='和'^~'都没有匹配上,暂存'最长'前缀匹配,开始进行'正则匹配'
(5) 如果'正则'匹配,则使用'正则匹配上'的,否则'使用之前暂存'的"最长前缀字符的location"
细节点: 不考虑'~'和'~*'正则的优先级,'正则'完全按照'配置'文件的顺序
++++++++++++ 'location / 兜底原因 ' ++++++++++++
1) 为了'避免'第1步中就'没有找到'能匹配上的前缀location,导致基于'root'直接返回'404'
2) 通常会在'末尾'添加'location / {}'兜底,它可以匹配'任意'URL,相当于'switch default'
⑦ 官方案例
⑧ @name 定义命名location
1: '修饰符@'用于定义一个'内部' location 块,该块'不能'被外部 client '直接'访问
2: 只能被 nginx '内部配置指令'所访问:比如 'try_files' 或者'error_page'
备注:'internal'也是'同样'的效果
+++++++++++ 'error_page'中 '@' 使用 +++++++++++
location 的'内部跳转'匹配符号'@':
location /index/ {
error_page 404 @index_error;
}
location @index_error {
return 404 'ok\n';
}
解读:以 /index/ 开头的请求,如果'现状态码是 404',则会匹配到 @index_error 这条'规则'上
+++++++++++ 'try_files'中 '@' 使用 +++++++++++
location / {
try_files $uri $uri/ @custom
}
location @custom {
# ...do something
}
⑨ location嵌套
说明: 了解'有这种用法'即可,下面进行了'详细'的解读
⑩ 加不加/问题
纠正: '/user'和'/user/'有区别的 --> /user会'返回301'和 'user/ 重定向'
二 location nested location
① 存在父子关系的location条件限制
+++++++++++++++ location共分为'四'种 +++++++++++++++
1) exact_match:"="类型,'精准'匹配;
2) noregx:"^~[特殊]"或""类型,'非正则'的特殊'前缀'匹配;
3) regex:"[!]~[*]",正则匹配;
4) named:"@"类型,'内部'跳转匹配,也是'精确匹配';
+++++++++++++++ 对于存在'父子关系'的location +++++++++++++++
1) 父只能是'noregex'或'regex'类型;
2) 子location'不能'是named类型;
3) 子的name'不能'包含父
+++++++++++ "一般正则嵌套的风格 [正常的]" +++++++++++
server {
location /images {
location /images/icons {
# ...
}
location /images/photos {
# ...
}
}
}
② 动作指令和值指令
1) 值指令:存储'配置项的值[静态]',是用来'配置'某一个配置项的,可以'继承|覆盖'
eg: root、add_header、access_log、index等
2) 动作类指令:指定行为'动作action',往往表示接下来'要做'一件事情,不可以'合并被继承'
eg: rewrite、proxy_pass、try_files、return
3) 指令分类:Normal、Array、Action、Action、try_files
Normal指令 - 每个上下文一个值,例如:"root"或"index"
Array指令 - 每个上下文可以有,'多个'值,例如:"access_log"或"add_header"
Action指令 - 不只是配置的东西,例如:"rewrite"
try_files指令 - 'server'或'location'上下文不同
4) 目的: 'location嵌套location',一些'继承和覆盖'问题,基本同之前'context'
备注:'子location'作用域名小于'父'location
Standard Type Directives Array Type Directives Command Type Directives
③ location嵌套改变find_location
location in location的优先级 原始嵌套解读
1) Exact string 'exact matches' location = /foo
2) The 'longest' of any location '^~' ... matches
3) The 'first (exact prefix |regex match)' that \
is nested within the single longest 'matching prefix' match!
备注:原文描述的结论'不准确',这里做了'修改'
4) The first 'other regex' match location '~' regex
5) The 'longest prefix match' location /foo
++++++++++ "案例讲解" ++++++++++
'难点'理解:
1) 如果对应'location'嵌套的是'prefix location',并且是'longest prefix match'
2) 重新按照'=、^~、regular'顺序在'子location'中寻找
不同点:在嵌套中'^~'是最长'前缀'匹配,会停止'该level的regular',但是不会停止'父regular'
grep -En 'test location|using configuration' /var/log/nginx/error.log '看过程'
案例1: '/wzj'请求
第'1'阶段:'/wzj' 是'最长'的前缀匹配,发现是'嵌套',然后'=和^~'都不匹配,则使用嵌套'regular'
案例2: '/wzj11'请求
第'1'阶段: '/wzj1 [最长的前缀匹配]',但不是'=、^~',不能停止'regular'
第'2'阶段: 使用 '~ wzj'
案例3: '/wzj22'请求
第'1'阶段: '/wzj [最长的前缀匹配]',查看该嵌套的'= /wzj22',则'停止'后续的location查找
思考: '/wzj222'呢? --> '~ /wzj(.*)' --> nested location regular 222 ok!
案例4: '/wzj3'请求
细节点:
1) 第'1'阶段: '/wzj [最长的前缀匹配]',查看该嵌套的'^~ /wzj3 [最长前缀匹配]'
2) 'nested location'中,'^~ /wzj3'使'该level'下的正则'~ ^/wzj(.*)'停止
3) 但是没有作为'最终的'location,而是'跳出嵌套location',继续寻找父regular '~ /wzj'
案例5: '/wzj33'请求 --> "同上"
nginx nested location add_header
三 相关参考
题外话:
1) location是基于'$uri'进行find_location匹配的
2) '$uri'是'decode解码'后的,'不带'查询参数;'$request_uri'是'原始 url encode的'带参
+++++++++++++ "动静态分离" +++++++++++++
1)如何识别'静态'页面,让'web服务器(nginx)'处理
常用: '/static'或者'\.(?:html|js|jpg)',通过'root指令'
2)如何识别'动态'页面,让'应用服务器(tomcat、django)'
常见: 'proxy_pass、grpc_pass、fastcgi_pass'
其它: rewrite ^/pets/rabbits/?$ /pets/rabbits.html last; --> '解决带不带/'的问题