Nginx之location 匹配规则详解

开篇

 最近刚好在极客世界地订阅了关于nginx的课程,也对公司通过nginx打点日志的实现比较感兴趣,所以抽空研究下nginx的location规则匹配逻辑。

 这篇文章转自互联网,在文章末尾注明了出处了,之所以转载是因为这篇文章讲解的比较清晰,适合像我这样的入门小白学习。有兴趣的可以参考着学习。


概念

location
syntax: location [=|~|~*|^~|@] /uri/ { … }
default: no
context: server



This directive allows different configurations depending on the URI.

译文:

  • 1 、different configurations depending on the URI 说的就是语法格式:location [= | ~ | ~* | ^~ | @] /uri/ { … } ,依据不同的前缀“= ”,“^~ ”,“~ ”,“~* ”和不带任何前缀的(因为[A] 表示可选,可以不要的),表达不同的含义, 简单的说尽管location 的/uri/ 配置一样,但前缀不一样,表达的是不同的指令含义

  • 2 、查询字符串不在URI范围内。例如:/films.htm?fid=123 的URI 是/films.htm 。



It can be configured using both literal strings and regular expressions. To use regular expressions, you must use a prefix:

  • 1、“~” for case sensitive matching
  • 2、“~*” for case insensitive matching

译文:

  • 1、上文讲到location /uri/ 可通过使用不同的前缀,表达不同的含义。对这些不同前缀分下类就2 大类:正则location(英文说法是location using regular expressions)和 普通location(英文说法是location using literal strings )。

  • 2、其中~~*前缀表示正则location ,~区分大小写,~不区分大小写;其他前缀(包括:=^~@*)和无任何前缀的都属于普通location 。



To determine which location directive matches a particular query, the literal strings are checked first.

译文:

  • 1、对于一个特定的 HTTP 请求(a particular query), nginx 应该匹配哪个 location 块的指令呢(注意:我们在 nginx.conf 配置文件里面一般会定义多个 location 的)?

  • 2、匹配 规则是:先匹配普通location (再匹配正则表达式)。注意:官方文档这句话就明确说了,先普通location ,而不是有些同学的误区“先匹配正则location ”。



Literal strings match the beginning portion of the query – the most specific match will be used.
译文:

  • 1、前面说了普通location正则location之间的匹配规则是:先匹配普通location ,再匹配正则location 。那么,普通location 内部(普通location 与普通location )是如何匹配的呢?简单的说:最大前缀匹配。

  • 2、原文:(1)、match the beginning portion of the query (说的是匹配URI 的前缀部分beginning portion ); (2) 、the most specific match will be used (因为location 不是“严格匹配”,而是“前缀匹配”,就会产生一个HTTP 请求,可以“前缀匹配”到多个普通location ,例如:location /prefix/mid/ {} 和location /prefix/ {} ,对于HTTP 请求/prefix/mid/t.html ,前缀匹配的话两个location 都满足,选哪个?原则是:the most specific match ,于是选的是location /prefix/mid/ {})



Afterwards, regular expressions are checked in the order defined in the configuration file. The first regular expression to match the query will stop the search.
译文:

  • 1、这段话说的第一层意思是:“Afterwards, regular expressions are checked ”, 意思是普通location 先匹配,而且选择了最大前缀匹配后,不能就停止后面的匹配,最大前缀匹配只是一个临时的结果,nginx 还需要继续检查正则location(但至于最终才能普通location 的最大前缀匹配,还是正则location 的匹配,截止当前的内容还没讲,但后面会讲)。

  • 2、这段话说的第二层意思是“regular expressions are checked in the order defined in the configuration file. The first regular expression to match the query will stop the search. ”,意思是说“正则location ”与“正则location”内部的匹配规则是:按照正则location 在配置文件中的物理顺序(编辑顺序)匹配的(这句话就说明location 并不是一定跟顺序无关,只是普通location 与顺序无关,正则location 还是与顺序有关的),并且只要匹配到一条正则location ,就不再考虑后面的(这与“普通location ”与“正则location ”之间的规则不一样

  • 3、“普通location ”与“正则location ”之间的规则是:选择出“普通location ”的最大前缀匹配结果后,还需要继续搜索正则location )。



If no regular expression matches are found, the result from the literal string search is used.
译文:

  • 1、这句话回答了“普通location ”的最大前缀匹配结果与继续搜索的“正则location ”匹配结果的决策关系。如果继续搜索的“正则location ”也有匹配上的,那么“正则location”覆盖“普通location ”的最大前缀匹配(因为有这个覆盖关系,所以造成有些同学以为正则location 先于普通location 执行的错误理解);但是如果“正则location ”没有能匹配上,那么就用“普通location ”的最大前缀匹配结果。



It is possible to disable regular expression checks after literal string matching by using “^~” prefix.If the most specific match literal location has this prefix: regular expressions aren’t checked.
译文:

  • 1、通常的规则是,匹配完了“普通location ”指令,还需要继续匹配“正则location ”,但是你也可以告诉Nginx :匹配到了“普通location ”后,不再需要继续匹配“正则location ”了,要做到这一点只要在“普通location ”前面加上“^~ ”符号(^ 表示“非”,~ 表示“正则”,字符意思是:不要继续匹配正则)。



By using the “=” prefix we define the exact match between request URI and location. When matched search stops immediately. E.g., if the request “/” occurs frequently, using “location = /” will speed up processing of this request a bit as search will stop after first comparison.
译文:

  • 1、除了上文的“^~ ”可以阻止继续搜索正则location 外,你还可以加“= ”。那么如果“^~ ”和“= ”都能阻止继续搜索正则location 的话,那它们之间有什么区别呢?区别很简单,共同点是它们都能阻止继续搜索正则location ,不同点是“^~ ”依然遵守“最大前缀”匹配规则,然而“= ”不是“最大前缀”,而是必须是严格匹配(exact match )

  • 2、这里顺便讲下“location / {} ”和“location = / {} ”的区别,“location / {} ”遵守普通location 的最大前缀匹配,由于任何URI 都必然以“/ ”根开头,所以对于一个URI ,如果有更specific 的匹配,那自然是选这个更specific 的,如果没有,“/ ”一定能为这个URI 垫背(至少能匹配到“/ ”),也就是说“location / {} ”有点默认配置的味道,其他更specific的配置能覆盖overwrite 这个默认配置(这也是为什么我们总能看到location / {} 这个配置的一个很重要的原因)。而“location = / {} ”遵守的是“严格精确匹配exact match ”,也就是只能匹配 http://host:port/ 请求,同时会禁止继续搜索正则location 。因此如果我们只想对“GET / ”请求配置作用指令,那么我们可以选“location = / {} ”这样能减少正则location 的搜索,因此效率比“location / {}” 高(注:前提是我们的目的仅仅只想对“GET / ”起作用)。



On exact match with literal location without “=” or “^~” prefixes search is also immediately terminated.
译文:

  • 1、前面我们说了,普通location 匹配完后,还会继续匹配正则location ;但是nginx 允许你阻止这种行为,方法很简单,只需要在普通location 前加“^~ ”或“= ”。但其实还有一种“隐含”的方式来阻止正则location 的搜索,这种隐含的方式就是:当“最大前缀”匹配恰好就是一个“严格精确(exact match )”匹配,照样会停止后面的搜索。原文字面意思是:只要遇到“精确匹配exact match ”,即使普通location 没有带“= ”或“^~ ”前缀,也一样会终止后面的匹配。

  • 2、先举例解释下,后面例题会用实践告诉大家。假设当前配置是:location /exact/match/test.html { 配置指令块1},location /prefix/ { 配置指令块2} 和 location ~ .html$ { 配置指令块3} ,如果我们请求 GET /prefix/index.html ,则会被匹配到指令块3 ,因为普通location /prefix/ 依据最大匹配原则能匹配当前请求,但是会被后面的正则location 覆盖;当请求GET /exact/match/test.html ,会匹配到指令块1 ,因为这个是普通location 的exact match ,会禁止继续搜索正则location 。

To summarize, the order in which directives are checked is as follows:

  1. Directives with the “=” prefix that match the query exactly. If found, searching stops.
  2. All remaining directives with conventional strings. If this match used the “^~” prefix, searching stops.
  3. Regular expressions, in the order they are defined in the configuration file.
  4. If #3 yielded a match, that result is used. Otherwise, the match from #2 is used.

这个顺序没必要再过多解释了。但我想用自己的话概括下上面的意思“正则 location 匹配让步普通location 的严格精确匹配结果;但覆盖普通 location 的最大前缀匹配结果”。


参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容