1 location 详解
1.location 匹配规则
Nginx 中 location 的作用是根据 Url 来决定怎么处理用户请求 (转发请求给其他服务器处理或者查找本地文件进行处理).location 支持正则表达式, 配置十分灵活. 我们可以在一个虚拟主机(nginx 中的一个 server 节点) 下配置多个 location 以满足如动静分离, 防盗链等需求.
location 语法是: location [=|~|~*|^~] /uri/ {... }, 具体解释如下表:
符号 | 含义 |
location = /url | = : 开头, 表示精确匹配, uri 必须完全一致才能匹配成功 |
location ^~ /Purl | ^~:Puri 和请求 url 的开头相同就匹配成功,且不再去匹配正则,也属于普通匹配 |
location /Purl | 普通匹配,Purl 和用户请求 url 的开头相同就匹配成功,如果有多个普通匹配都匹配成功则按最长的 。 如有 location /static/, 和 oaction /static/img/ 当请求是 www.mysite.com/static/img/1.jpg 时,第二个 location 匹配的更长,所以和第二个 loaction 匹配成功。 |
location ~ reg | ~ :区分大小写的正则匹配 |
location ~* reg | ~* : 不区分大小写的正则匹配 |
location 的匹配顺序是: = /url > ^~ /Purl >/Purl> ~ 和 ~* , 具体流程如下图所示, 需要注意: 一般情况下, 匹配成功了普通字符串 location 后还会进行正则表达式 location 匹配. 两种情况除外:1使用 "=", 即精准匹配, 如果匹配成功就立即停止其他匹配;2使用 "^~" 前缀, 这个前缀告诉 nginx , 如果匹配成功不再进行正则匹配.
简单总结:
1. 先进行精准匹配, 如果匹配成功, 立即返回结果并结束匹配过程.
2. 进行普通匹配, 如果有多个 location 匹配成功, 将 "最长前缀" 的 location 作为临时结果(如果是 ^~ 类型的普通匹配成功则直接返回结果, 结束匹配过程).
3. 由上至下逐一进行正则匹配, 一旦匹配成功 1 个, 立即返回结果, 并结束解析过程; 如果没有一个正则匹配成功, 那么将普通匹配的最长前缀 location 作为最终结果返回, 并结束匹配过程.
2. 实际使用建议
实际使用中, 个人觉得每个虚拟主机下 (server 节点下) 至少有三个匹配规则定义, 如下:
- # 直接匹配网站根, 通过域名访问网站首页比较频繁, 使用这个会加速处理, 官网如是说.
- # 这里是直接转发给后端应用服务器了, 也可以是一个静态首页
- # 第一个必选规则
- location = / {
- proxy_pass http://tomcat:8080/index
- }
- # 第二个必选规则是处理静态文件请求, 这是 nginx 作为 http 服务器的强项
- # 有两种配置模式, 目录匹配或后缀匹配, 任选其一或搭配使用
- location ^~ /static/ {
- root /webroot/static/;
- }
- location ~* \.(gif|jpg|jpeg|PNG|CSS|JS|ico)$ {
- root /webroot/res/;
- }
- # 第三个规则就是通用规则, 用来转发动态请求到后端应用服务器
- # 非静态文件请求就默认是动态请求, 自己根据实际把握
- # 毕竟目前的一些框架的流行, 带. PHP,.jsp 后缀的情况很少了
- location / {
- proxy_pass http://tomcat:8080/
- }
实际使用建议参考自: https://segmentfault.com/a/1190000002797606
2 rewrite 详解
1 rewrite 简单认识
rewrite 模块即 ngx_http_rewrite_module 模块, 主要功能是实现 URI 重定向. rewrite 模块会通过正则匹配重写 URI, 然后内部跳转再匹配 location, 或者直接做 30x 重定向返回客户端. Nginx 的 rewrite 功能需要 PCRE 的支持, PCRE 是 perl 兼容正则表达式库. rewrite 指令的语法十分简单如下:
rewrite 将符合正则的内容替换为新的替代内容
rewrite <regex> <replacement> [flag];
关键字 正则 替代内容 flag 标记
正 则: perl 兼容正则表达式语句进行规则匹配
替代内容: 将正则匹配的内容替换成 replacement
flag 标记: rewrite 支持的 flag 标记
-------------------------------------------------------------------------------
flag 标记说明:
- last #匹配完成后不再匹配当前环境下的其他 rewrite 指令, 开始匹配新的 location URI 规则
- break #匹配完成即终止, 不再匹配后面的任何规则
- redirect #返回 302 临时重定向, 浏览器地址会显示跳转后的 URL 地址
- permanent #返回 301 永久重定向, 浏览器地址栏会显示跳转后的 URL 地址
使用 rewrite 时也会用到, 几个常用的指令汇总如下:
指令 | 使用范围 | 作用 |
if ( condition ){ // 符合条件执行} | location,server | 条件判断。 = != 判断是否相等 ~ ~* 判断是否符合正则 -e !-e 判断文件,目录,符号链接是否存在 -d !-d 判断目录是否存在 -f !-f 判断文件是否存在 -x !-x 判断是否可执行 |
break | server,location,if | 不再继续执行任何指令,直接退出规则的执行 |
return | server,location,if | 结束规则的执行和返回状态码给客户端;如 return 403; |
set variable ‘value’ | http,server,location,if | 新建变量,并赋值 ;如 set varx 'hello' |
一个简单的栗子, 简单了解下 rewrite:
- server{
- listen 80;
- server_name www.mysite.com;
- #在 server 中调转到 爱奇艺
- #rewrite ^/(.*) https://www.iqiyi.com break;
- location = /{
- #location 中跳转到百度
- rewrite ^/(.*) http://www.baidu.com;
- root html;
- index index.HTML;
- }
- #日志记录
- error_log logs/mysite.error.log error;
- access_log logs/mysite.access.log main;
- }
我们知道默认情况访问 nginx 的虚拟主机会展示 nginx 的欢迎界面, 我们通过 rewrite 指令跳转到百度. 输入虚拟机的 IP, 访问结果不再是 nginx 欢迎页, 而是 302 跳转到百度如下:
2 rewrite 的执行过程
nginx 中我们可以有多个 rewrite 指令, 默认情况下 rewrite 从上到下依次执行, 并按最后一个匹配成功的作为最终结果. 一种特殊情况是当 replacement 中包含 http/https 等协议名时, 直接 302 跳转到 replacement 指定的 url, 不再执行后续的 rewrite 指令.
那么如果我们想在执行一条 rewrite 指令后不再执行后续指令怎么办呢? 这时就可以用 rewrite 中的 flag 标记, 四种 flag 标记都可以实现不再往下执行其他 rewrite 指令的作用, 但是每种 flag 标记的使用场景不同. 介绍语法的时候已经介绍了四种 flag 的作用, 我们来看一个栗子吧:
- server{
- listen 80;
- server_name www.mysite.com;
- location = /{
- #跳转到百度
- rewrite ^/(.*) http://www.baidu.com;
- #跳转到 / test1
- rewrite ^/(.*) /test1;
- #跳转到 / test2
- rewrite ^/(.*) /test2;
- root HTML;
- index index.HTML;
- }
- location /test1{
- return 401;
- }
- location /test2{
- return 402;
- }
- #日志记录
- error_log logs/mysite.error.log error;
- access_log logs/mysite.access.log main;
- }
server 进行上边的配置时, 我们访问虚拟机 IP 192.168.70.132, 会跳转到百度页面, 因为 replacement 包含了 http 协议名, 不在执行后续的 rewrite 指令;
如果把第一个 rewrite 注释掉, 会调整到 402 错误页, 因为 rewrite 的最终结果时以最后一个匹配成功的为准, 最后匹配到 rewite /test2 指令, 然后找到 location /test2 返回 402 错误码;
如果我们在 rewrite ^?(.*) /test1 后边加上 last 标记 , 表示不再匹配后边的 rewrite, 会跳到 401 错误页, url 不变还是 http://192.168.70.132;
如果我们在 rewrite ^?(.*) /test1 后边加上 redirect 或者 permanent 标记 , 表示不再匹配后边的 rewrite, 会跳转到 401 错误页(redirect 的跳转码为 302,permanet 的跳转码时 301),url 会改变成 http://192.168.70.132/test1;
如果我们在 rewrite ^?(.*) /test1 后边加上 break 标记 , 表示不再匹配任何规则, 会跳转到 404 错误页; 因为 break 标记不会再执行任何规则, 所以不会再去找 location test1, 而是直接找 HTML/test1 资源, 所以出现 404 错误.
3 一些常用的全局变量
在使用 rewrite 指令时我们经常会用到一些常用的全局变量, 这些全局变量定义在 nginx/conf/fastcgi.conf 中, 列举如下:
变量 | 含义 |
$args | 请求中的参数,同 $query_string |
$content length | 请求头中的 Content-length 字段。 |
$content_type | 请求头中的 Content-Type 字段。 |
$document_root | 当前请求在 root 指令中指定的值。 |
$host | 请求主机头字段,否则为服务器名称。 |
$http_user_agent | 用户代理,一般为用户浏览器信息 |
$http_cookie | 客户端 cookie 信息 |
$limit_rate | 这个变量可以限制连接速率。 |
$request_method | 客户端请求的动作,通常为 GET 或 POST。 |
$remote_addr | 客户端的 IP 地址。 |
$remote_port | 客户端的端口。 |
$remote_user | 已经经过 Auth Basic Module 验证的用户名。 |
$request_filename | 当前请求的文件路径,由 root 或 alias 指令与 URI 请求生成。 |
$scheme | 协议名(如 http,https)。 |
$server_protocol | 请求使用的协议,通常是 HTTP/1.0 或 HTTP/1.1。 |
$server_addr | 服务器地址,在完成一次系统调用后可以确定这个值。 |
$server_name | 服务器名称。 |
$server_port | 请求到达服务器的端口号。 |
$request_uri | 包含请求参数的原始 URI,不包含主机名,如”/user/getuser?id=100”。 |
$uri | 不带请求参数的当前 URI,$uri 不包含主机名,如”/user/getuser”。 |
$document_uri | 与 $uri 相同。 |
这里列举几个 rewrite 的简单栗子来帮助理解:
1 禁止特定 IP 访问
- server{
- listen 80;
- server_name localhost;
- location /{
- #如果客户端 IP 是 192.168.70.1, 那么拒接响应
- if ($remote_addr = 192.168.70.1){
- return 403;
- }
- root HTML;
- index index.HTML;
- }
- }
通过 IP 为 192.168.70.1 的电脑去访问时, 结果如下:
2 根据浏览器不同跳转到不同页面
- # 如果是 google 访问的, 重定向到 HTML/Chrome.HTML 页面
- location /{
- if ($http_user_agent ~ Chrome){
- rewrite ^.*$ /Chrome.HTML;
- break;
- }
- root HTML;
- index index.HTML;
- }
3 文件不存在返回 404, 写的比较繁琐, 主要是演示 rewrite 的用法
- server{
- listen 80;
- server_name www.mysite.com;
- location /{
- #如果文件不存在, 跳转到 notfound,
- if (!-f /usr/local/nginx/HTML/aaa.HTML){
- rewrite ^/(.*) /notfound ;
- }
- root HTML;
- index index.HTML;
- }
- location ~ /notfound {
- return 404;
- }
- error_log logs/mysite.error.log error;
- access_log logs/mysite.access.log main;
- }
小结: loaction 和 rewrite 是 nginx 中最核心的指令, 通过 location 和 rewrite 我们可以实现动静分离 / 规范客户端 url 等功能, 因为支持 perl 的正则表达式, 用法十分灵活. 这里简单做了一些总结, 如果有不正确的地方请指出.
参考文章:
[1] https://www.cnblogs.com/coder-yoyo/p/6346595.html
[2] https://www.cnblogs.com/czlun/articles/7010604.html
[3] https://www.cnblogs.com/crazylqy/p/6892010.html
来源: https://www.cnblogs.com/wyy1234/p/10632108.html