## 7.认识Nginx中的location和正则表达式,一起啃这块硬骨头(上篇) 【初识location阶段】 Nginx的location,我们在上一个篇幅中 跟大家提过,确实很不好理解 是不是还是心有余悸呢 (会者不难 不用太担心) 记不记得 我们之前讲过,nginx处理一个请求的时候,都是按用户输入的URL为基准,然后从左至右的来处理的 如果拆开来看一个URL 是这样的 ([http://nginx.org:80/static/](http://nginx.org/static/)) \-> http:// -> nginx.org -> :80 -> /static/ URL按照顺序被拆分开来后,相应的 nginx也会调用不同的模块和子模块 来进行处理 大体按照如下这样的顺序 http{}模块 -> server{}模块 -> location模块 下面咱们 通过之前的一段配置来一起看一下 会更明白一些 server { listen 80; server\_name html.example.com; access\_log /var/log/nginx/access\_html2.log html\_log; ```plain location / { proxy_pass http://html/index.html; access_log /var/log/nginx/access_html.log html_log; } } ``` 上面这段配置中,用户URL输入的 域名和端口 被server{}模块自身就匹配并处理了 而域名和端口匹配上之后,接下来 就是以一个 最右边结尾的 '/' 作为分隔符,再往右的部分 我们称作 "路径" 那么 这个"路径"的匹配 ,就只能交给谁来做呢? 自然就是location{}啦 :) location的作用 就是用来判断 用户在URL中 输入的"路径"的不同,然后再给导向到不同页面或者位置 (一个网站 总不能仅仅存在一个首页吧,总还得有其他的分页面吧,不然谁还会去浏览呢? 所以 就是有了路径区分页面,而相对的也就有了 处理路径的 location ) 接下来 我们先把nginx配置成如下这个样子 ```plain server { listen 80; server_name dami01.example.com; location / { return 201; } location = /nginx { return 202; } location /nginx { return 203; } location ~ /Nginx { return 204; } location ~* /nginx { return 205; } location ~ \.jpg$ { return 206; } location ~ /login/ { root /var/www/html/vhost/dami01.example.com/; } ``` } 先简单解释一下 上面这一段的配置文件 可以看到server下 有很多个location并列的放在一起 每一个location表示一种匹配的方法 另外,location中 我们调用了 return 2xx, 这个是代表 一旦匹配上了 就给予不同的返回值 (不同的返回值的目的 就为了让我们在测试的时候 一目了然 知道自己的输入被哪一项location匹配上了 ok? ) 那么location到底是通过什么方式 来匹配用户的输入呢? 简单的说 就是location的写法 分成三个部分 : location关键字 + 匹配符号 + 路径字段 例如: location + = + /nginx 而理解的难点,在于中间的 匹配符号这里 ,因为说实在的 这里只能靠死记硬背 并没有什么规则可循 我们接下来 还是直接通过 例子 和 实验 来学习吧 首先 咱们看第一项 ```plain location / { return 201; } ``` 这一项 代表默认匹配 ,这样的写法就是说 如果其他的location全都匹配不上的时候,就回来找这一项来匹配 所以说 这个默认匹配的优先级是最低的 ,但分后面有一项能匹配上 也不会回来找它 ,除非是乱输入 接下来 我们就来试一试 用如下的方法 curl -I 查看返回码的方式来进行测试 \[root@server01 ~\]# curl -I [http://dami01.example.com/sdfsdfsdfsdfsdf](http://dami01.example.com/sdfsdfsdfsdfsdf) HTTP/1.1 201 Created Server: nginx/1.14.1 Date: Sat, 05 Jan 2019 04:57:30 GMT Content-Type: application/octet-stream Content-Length: 0 Connection: keep-alive \[root@server01 ~\]# curl -I [http://dami01.example.com/hahaha](http://dami01.example.com/hahaha) HTTP/1.1 201 Created Server: nginx/1.14.1 Date: Sat, 05 Jan 2019 04:57:34 GMT Content-Type: application/octet-stream Content-Length: 0 Connection: keep-alive 看到了没? 测试的时候 即便胡乱的输入URL(胡乱输入URL的路径 那肯定别的location都匹配不上了),最终都会匹配到 咱们的第一项默认location 因为 location / 指的是,只要你路径中以 / 开头了 不管你后面输入啥 都能匹配到(路径无论如何 都会以 / 起头)。于是返回201 (201是怎么自己设置的 为了观察) 好的 接下来 咱们看第一项和第二项和第三项在一起的情况 ```plain location / { return 201; } location = /nginx { return 202; } location /nginx { return 203; } ``` 第二项这个 location = /nginx , 这里需要重点给大家强调一下了 单独一个 = 号, 代表的是 最高优先级+精准匹配 !! 什么意思呢? 首先最高优先级 意思是说,只要用户输入的URL 能匹配上这一条,那么其他的location一律全忽略掉(就算其他的也可以匹配上 都不管了) 只调用这里的 精准匹配 是什么意思呢? 就是 一点都不能差! 也就是说,= 后面写的内容 和 用户输入的路径 必须完全完全一模一样 ,稍有变化 则匹配不上了 接下来 咱们做实验吧 我们按照如下 这样输入URL, 返回202 \[root@server01 ~\]# curl -I [http://dami01.example.com/nginx](http://dami01.example.com/nginx) HTTP/1.1 202 Accepted Server: nginx/1.14.1 Date: Sat, 05 Jan 2019 05:06:13 GMT Content-Type: application/octet-stream Content-Length: 0 Connection: keep-alive 返回202 说明被下面的location 匹配上了,而且是精准匹配 ,因为 用户输入的 /nginx 和 location = 后面的 /nginx 一模一样 ,多一个别的字符都没有 ```plain location = /nginx { return 202; } ``` 一旦被 这个location的精确匹配抓到了,那么后面的 返回203的location 即便匹配上了 也没用了 接下来 咱们再换一种 输入方式 \[root@server01 ~\]# curl -I [http://dami01.example.com/nginx/](http://dami01.example.com/nginx/) HTTP/1.1 203 Server: nginx/1.14.1 Date: Sat, 05 Jan 2019 05:09:32 GMT Content-Type: application/octet-stream Content-Length: 0 Connection: keep-alive \[root@server01 ~\]# \[root@server01 ~\]# curl -I [http://dami01.example.com/nginxsdfasdf](http://dami01.example.com/nginxsdfasdf) HTTP/1.1 203 Server: nginx/1.14.1 Date: Sat, 05 Jan 2019 05:09:39 GMT Content-Type: application/octet-stream Content-Length: 0 Connection: keep-alive 注意 这次输入的URL有变化了, 第一个是 /nginx/ 第二个是 /nginxsdasdf 首先 ,这两次的输入 返回203 是被如下第三项location抓到了 ```plain location /nginx { return 203; } ``` 为什么第二项location(返回202的) 抓不到了呢? 因为 这两次 咱们的输入 是 /nginx/ 和 /nginxsdasdf , 而 location = /nginx 可是眼睛里不揉沙子哦 必须输入的一模一样 多一个少一个字符都不行 而第三项 location /nginx 这个就相对宽松太多了, 它的意思是 只要用户输入的路径以 /nginx起始就行,后面的部分 随便输入什么 都无所谓 都可以匹配上 所以说 /nginx/ 和 /nginxsdasdf 这样的输入,都是满足了 前面以"/nginx"开头,后面再随意的输入 好的 接下来 咱们看 第四项和第五项规则 ```plain location ~ /Nginx/$ { return 204; } location ~* /nginx/$ { return 205; ``` 先做一个简单的说明吧 location ~ 代表的是 区分大小写的正则表达式 location ~\* 代表的是 不区分大小写的正则表达式 204这一项代表的是,用户输入的nginx 必须开头字母大写,而且最后还必须是 '/'结尾 才能匹配上 ($意思是 以某个字符结尾, /$ :以'/' 结尾) 而205这一项 代表的是 不区分大小写,但也得以 / 结尾 接下来咱们做实验吧 \[root@server01 ~\]# curl -I [http://dami01.example.com/Nginx/](http://dami01.example.com/Nginx/) HTTP/1.1 204 No Content Server: nginx/1.14.1 Date: Sat, 05 Jan 2019 05:27:07 GMT Connection: keep-alive \[root@server01 ~\]# curl -I [http://dami01.example.com/NgiNx/](http://dami01.example.com/NgiNx/) HTTP/1.1 205 Server: nginx/1.14.1 Date: Sat, 05 Jan 2019 05:27:18 GMT Content-Type: application/octet-stream Content-Length: 0 Connection: keep-alive \[root@server01 ~\]# curl -I [http://dami01.example.com/ngiNx/](http://dami01.example.com/ngiNx/) HTTP/1.1 205 Server: nginx/1.14.1 Date: Sat, 05 Jan 2019 05:27:25 GMT Content-Type: application/octet-stream Content-Length: 0 Connection: keep-alive 第一次的测试,因为咱们完全符合了 204的规则,开头N大写,并且以/结尾 ,所以被204 location匹配抓到 后面的两次测试,由于我们没有遵守大小写的规定,但是依然是 nginx这个词,并且以/结尾,所以205location匹配到 再加入一项 ```plain location ~ \.jpg$ { return 207; } ``` 这种代表的是 以.jpg结尾 我们当前的配置是 ```plain location / { return 201; } location = /nginx { return 202; } location /nginx { return 203; } location ~ /Nginx/$ { return 204; } location ~* /nginx/ { return 205; } location ~ \.jpg$ { return 206; } ``` 接下来 咱们来做实验吧 \[root@server01 ~\]# curl -I [http://dami01.example.com/1.jpg](http://dami01.example.com/1.jpg) HTTP/1.1 206 Partial Content Server: nginx/1.14.1 Date: Sat, 05 Jan 2019 05:40:43 GMT Content-Type: image/jpeg Content-Length: 0 Connection: keep-alive \[root@server01 ~\]# curl -I [http://dami01.example.com/abc.jpg](http://dami01.example.com/abc.jpg) HTTP/1.1 206 Partial Content Server: nginx/1.14.1 Date: Sat, 05 Jan 2019 05:40:45 GMT Content-Type: image/jpeg Content-Length: 0 Connection: keep-alive \[root@server01 ~\]# \[root@server01 ~\]# curl -I [http://dami01.example.com/nginx/1.jpg](http://dami01.example.com/nginx/1.jpg) HTTP/1.1 205 Server: nginx/1.14.1 Date: Sat, 05 Jan 2019 05:40:51 GMT Content-Type: image/jpeg Content-Length: 0 Connection: keep-alive 从上面 咱们可以看出,不管路径怎么随便输入,只要咱们的URL中 出现了以 '.jpg'结尾,就可以被206匹配到 但是注意最后一次的 当咱们的URL是 /nginx/1.jgp的时候, 返回的是205了 这就说明 ~\* /nginx/ 被匹配上了 并且 优先级 还比 ~ .jpg 高 ,所以 206被忽略了 大家私下里 就可以使用这种 location + return的方法 快速的自己测试 各种location匹配的方法 以及优先级 除此之外, location{} 括号之中的内容 ,可以单独定义 root , 也可以单独定义 proxy\_pass 比如,被某一个location匹配上后,就跳到某一个页面去,或者被反向代理到另一个位置去 等等 更多的内容 我们在下篇中 再继续 ^\_^