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 的最大前缀匹配结果”。


参考

  • Nginx之location 匹配规则详解

你可能感兴趣的:(Nginx之location 匹配规则详解)