前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >nginx location配置

nginx location配置

作者头像
腾讯IVWEB团队
发布2020-09-22 11:14:30
3.4K1
发布2020-09-22 11:14:30
举报

编写本文时,使用的nginx版本为nginx/1.17.9和nginx/1.16.1

路由匹配规则

location路由匹配的大致规则:location [=|^~|~|~*|@] path { ... }

如果大家对这块内容比较熟悉了,可以直接到优先级疑惑点这里看一个比较奇怪的匹配逻辑。

精确匹配(=)

location配置的path和客户端请求的path完全一致时匹配成功。

匹配成功后,nginx就会停止搜索其他匹配项。

代码语言:javascript
复制
server {
  listen 2020;

  location = /test {
    return 200 '=';
  }
}
  • 请求localhost:2020/test,匹配成功,响应内容为"="
  • 请求localhost:2020/test?num=1,匹配成功,响应内容为"="
  • 请求localhost:2020/test/,匹配失败,响应状态码404
  • 请求localhost:2020/test/1,匹配失败,响应状态码404

前缀匹配(^~)

location配置的path为客户端请求的path前缀时匹配成功。

匹配成功后,nginx还会判断是否存在后面这种情况{(location修饰符为^~ || location没有修饰符) && location配置的path是客户端请求的前缀},如果存在,就使用匹配项最多的作为最后的匹配结果。

代码语言:javascript
复制
server {
  listen 2020;

  location ^~ /test {
    return 200 '^~';
  }
}
  • 请求localhost:2020/test,匹配成功,响应内容"^~"
  • 请求localhost:2020/test/1,匹配成功,响应内容"^~"
  • 请求localhost:2020/test111,匹配成功,响应内容"^~"
  • 请求localhost:2020/tes,匹配失败,响应状态码404
代码语言:javascript
复制
server {
  listen 2020;

  location ^~ /test {
    return 200 '/test';
  }

  location ^~ /test/1 {
    return 200 '/test/1';
  }
}
  • 请求localhost:2020/test,匹配成功,响应内容"/test"
  • 请求localhost:2020/tes,匹配成功,响应内容"/test"
  • 请求localhost:2020/test/1,匹配成功,响应内容"/test/1"。这里两个location配置都匹配上了,第一个location匹配项为1,第二个location匹配项为2,由于nginx选用匹配项最多的location,所以响应内容"/test/1"。

正则匹配(~ 和 ~*)

修饰符~,正则匹配区分大小写。修饰符~*,正则匹配不区分大小写。

正则匹配以location在文件中的定义顺序从上到下进行匹配。匹配成功以后,nginx就停止搜索其他匹配项。

注意:mac os文件系统大小写不敏感,因此nginx服务配置的location path不区分大小写,nginx使用~和~效果是一样的。linux文件系统大小写敏感,因此nginx服务区分大小写,nginx使用~和~效果与前面介绍的效果一致。

~例子
代码语言:javascript
复制
server {
  listen 2020;

  location ~ /test_a {
    return 200 '~';
  }
}
  • 请求localhost:2020/test_a,匹配成功,响应内容"~"
  • 请求localhost:2020/test_A,匹配成功和失败都有可能,得看nginx服务所在的系统对于大小写是否敏感。mac os系统下,匹配成功,响应内容"~";linux系统下,匹配失败,响应状态码404。
~*例子
代码语言:javascript
复制
server {
  listen 2020;

  location ~* /test_a {
    return 200 '~*';
  }
}
  • 请求localhost:2020/test_a,匹配成功,响应内容"~*"
  • 请求localhost:2020/test_A,匹配成功,响应内容"~*"

优先级

注:优先级从上到下依次递减。

  1. 精确匹配(=)
  2. 前缀匹配(^~)
  3. 正则匹配(~和~*)
  4. 通配符路径(没有任何修饰符,只有一个通配符路径"/")

下面我们使用不同的location配置组合来匹配location:2020/test_a这个请求。

代码语言:javascript
复制
server {
  listen 2020;

  location ^~ /test_a {
    return 200 '^~';
  }

  location = /test_a {
    return 200 '=';
  }
}
  • 请求localhost:2020/test_a,匹配成功,响应内容"=",精确匹配优先级比前缀匹配优先级大

代码语言:javascript
复制
server {
  listen 2020;

  location ~ /test_a {
    return 200 '~';
  }

  location ^~ /test_a {
    return 200 '^~';
  }
}
  • 请求localhost:2020/test_a,匹配成功,响应内容"^~",前缀匹配优先级比正则匹配优先级大

代码语言:javascript
复制
server {
  listen 2020;
  
  location / {
    return 200 '/';
  }

  location ~ /test_a {
    return 200 '~';
  }
}
  • 请求localhost:2020/test_a,匹配成功,响应内容"~",正则匹配优先级比通配符优先级大

优先级疑惑点

代码语言:javascript
复制
server {
  listen 2020;

  location ^~ /test {
    return 200 '~';
  }
  
  location /test/a {
    return 200 'null';
  }
}
  • 请求localhost:2020/test/a,匹配成功,响应内容"null",可以知道第二个location配置优先级比前缀优先级大,这个在前面前缀匹配有介绍。

我们将配置改成下面这个内容:

代码语言:javascript
复制
server {
  listen 2020;
  
  location /test {
    return 200 'null';
  }

  location ^~ /test {
    return 200 '~';
  }
}

然后运行nginx -t来检测配置文件是否正确,得到的结果是:nginx: [emerg] duplicate location "/test" in ...,这里的意思是路径为/test的location重复了。看到这里,原本以为"^~"是nginx定义location时默认的修饰符,但是,实际可能并不是,我们看下面的例子。


代码语言:javascript
复制
server {
  listen 2020;
  
  location ~ /test {
    return 200 '~';
  }
  
  location /test/a {
    return 200 'null';
  }

  location ^~ /test {
    return 200 '~';
  }
}
  • 请求localhost:2020/test/a,匹配成功,响应内容"~"(what?为什么返回的不是"null"),这里三个都匹配上了,但是nginx选用的是正则匹配结果,这个我不知道是什么原因,如果有大佬知道原因,还请大佬帮忙解惑。

location常用的参数

root & alias

两个参数都是用来指定文件路径。

注:之前很多文章都表示alias配置的路径最后必须加上"/",这个到现在已经不适用了。我测试的时候,alias配置的路径最后不添加"/",一样可以正常使用。

最终指向的文件路径区别
  • root指向的文件实际路径:root+location
  • alias指向的文件实际路径:alias
代码语言:javascript
复制
server {
  listen 2020;
  
  location /test {
    root /data;
  }
}

最终指向的文件路径为/data/test

代码语言:javascript
复制
server {
  listen 2020;
  
  location /test {
    alias /data;
  }
}

最终指向的文件路径为/data;

使用上面的配置,我们发起请求localhost:2020/test/1.png

  • root配置,该请求查找的文件路径为/data/test/1.png
  • alias配置,该请求查找的文件路径为/data/1.png
定义位置区别
  • root可以在http、server、location、if中定义内容
  • alias只能在location中定义

root在http、server定义以后,location会默认继承上层定义的内容,可以在location中使用root对上层root定义进行重写,或者使用alias让上层root在该lcation中失效。

正则匹配时定义区别
  • root:按照前面说的方式使用
  • alias:需要将正则匹配的内容添加到alias定义的路径后面,具体的例子如下
代码语言:javascript
复制
server {
  listen 2020;
  
  location ~ /test {
    alias /data;
  }
}

请求localhost:2020/test/1.png,匹配成功,但是没有找到文件内容,响应404

代码语言:javascript
复制
server {
  listen 2020;
  
  location ~ /test(.*)$ {
    alias /data$1;
  }
}

请求localhost:2020/test/1.png,匹配成功,能够正常返回文件

proxy_pass

该参数用作反向代理,可以用来做负载均衡、前端解决跨域等功能。使用结构proxy_pass url

关于proxy_pass实现负载均衡,可以在nginx负载均衡中看到相关内容。

proxy_pass转发请求,配置的url最后是否有"/",会呈现不同的效果。

代码语言:javascript
复制
server {
  listen 2020;
  
  location /api/ {
    proxy_pass http://localhost:7001;
  }
}

请求localhost:2020/api/component/list,nginx会将该请求代理转发到http://locahost:7001/api/component/list

应用场景:前端请求存在跨域,后端接口格式是api/业务路由,前端请求的接口也是api/业务路由

代码语言:javascript
复制
server {
  listen 2020;
  
  location /api/ {
    proxy_pass http://localhost:7001/;
  }
}

请求localhost:2020/api/component/list,nginx会将该请求代理转发到http://locahost:7001/component/list

应用场景:后端接口格式是业务路由,前端请求的接口是api/业务路由,前端请求的接口前面加一个"api"是为了标识某个后端服务,后端接口中并没用这个标识。


代码语言:javascript
复制
server {
  listen 2020;
  
  location /api/ {
    proxy_pass http://localhost:7001/online;
  }
}

请求localhost:2020/api/component/list,nginx会将该请求代理转发到http://locahost:7001/onlinecomponent/list

应用场景:没遇到这样的场景,一般都会用都会用"/"隔开路径。

代码语言:javascript
复制
server {
  listen 2020;
  
  location /api/ {
    proxy_pass http://localhost:7001/online/;
  }
}

请求localhost:2020/api/component/list,nginx会将该请求代理转发到http://locahost:7001/online/component/list

rewrite

rewrite参数用来将客户端请求重定向到一个新的地址。使用格式rewrite regex replacement [flag];

  • regex(必填):正则匹配,只有正则匹配成功后,才能进行地址修改等后续步骤
  • replacement(必填):新的url(以http:// https:// $schema等开头)或者uri,正则匹配成功后会用这个值替换原来的请求地址。当replacement值是url时,客户端请求发生重定向,因此会有两次请求,第一次请求是客户端原请求,响应的状态码为302,第二次请求的地址就是replacement值,本次rewrite逻辑运行完成以后,后续的rewrite不再匹配;当replacement值为uri时,客户端请求可能发生重定向,是否发生重定向与flag参数有关
  • flag(可选)
    • break:本条rewrite逻辑运行完成以后,后续的rewrite不再匹配
    • last:本条rewrite逻辑运行完成以后,后续的rewrite不再匹配,重新开始location路由匹配
    • permanent:永久重定向,301
    • redirect:临时重定向,302

下面展示几个例子:

代码语言:javascript
复制
server {
  listen 2020;
  
  location / {
    rewrite /(.*) https://www.$1.com;
  }
}

请求localhost:2020/baidu,请求被重定向到https://www.baidu.com

代码语言:javascript
复制
server {
  listen 2020;
  
  location / {
    rewrite (.*) https://www.baidu.com;
    rewrite (.*) https://www.github.com;
  }
}

请求localhost:2020,请求被重定向到https://www.baidu.com,查看network,里面有一条http://localhost:2020/请求,响应的状态码为302,还以一条https://www.baidu.com/请求。


代码语言:javascript
复制
server {
  listen 2020;
  
  location / {
    rewrite (.*) /test redirect; # permanent也是可以的
  }
  
  location /test {
    return 200 'ok';
  }
}

请求localhost:2020,请求被重定向到http://localhost:2020/test,network中有两条请求分别是响应状态码302(flag值为permanent时,状态码为301)的http://localhost:2020/请求和响应状态码为200的http://localhost:2020/test请求。


flag值为break或last都会终止后续rewrite匹配(不会终止proxy_pass等逻辑),两者不同的点是,break不会发起一轮新的location路由匹配,而last会发起一轮新的location匹配。

代码语言:javascript
复制
server {
  listen 2020;
  
  location /last {
    rewrite /last(.*) /test1;
    rewrite /test1(.*) /test2 last;
    rewrite /test2(.*) /test3;
  }
  
  location /break {
    rewrite /break(.*) /test1;
    rewrite /test1(.*) /test2 break;
    rewrite /test2(.*) /test3;
  }

  location /test1 {
    return 200 'test1';
  }

  location /test2 {
    return 200 'test2';
  }

  location /test3 {
    return 200 'test3';
  }
}
  • 请求localhost:2020/last,响应内容"test2"。这个请求被location /last {...}匹配成功,因为rewrite /test1(.*) /test2 last这里flag为last,所以这条rewrite逻辑运行完以后,就会忽略后续的rewrite,然后重新location路由匹配,重新匹配时请求变成http://localhost:2020/test2,因此会被location /test2 {}这条location匹配,所以响应内容为"test2"。
  • 请求localhost:2020/break,响应状态码为404。这个请求被location /break {...}匹配成功,因为rewrite /test1(.*) /test2 break这里flag为break,所以这条rewrite逻辑运行完以后,就会忽略后续的rewrite,执行完当前location后还是没有找到资源文件,因此返回状态码"404"。

将上面例子中location /break {...}这部分内容修改一下,修改成如下内容:

代码语言:javascript
复制
location /break {
    rewrite /break(.*) /test1;
    rewrite /test1(.*) /test2 break;
    rewrite /test2(.*) /test3;
    
    proxy_pass http://localhost:2020;
}
  • 请求localhost:2020/break,响应内容"test2",rewrite语句中flag值为break,不会影响proxy_pass语句,因此localhost:2020/break实际会代理转发到localhost:2020/test2这个地址。

如果rewrite部分内容没有看懂,可以到搞懂nginx的rewrite模块查看更详细的介绍。

index

index用于指定网站的起始页面,默认值index index.html;

index参数只是用来指定文件的路径,nginx根据index参数查找文件是否存在,如果存在就用文件路径拼接成新的url,nginx内部重定向到这个新的url,来获取到起始页面资源。下面用具体的例子来进行说明(/data/test目录下有一个index.html文件):

代码语言:javascript
复制
server {
  listen 2020;
  
  location / {
    root /data/test;
    index index.html;
  }
}

请求localhost:2020,响应内容为文件/data/test/index.html内容。

下面对配置文件添加一些内容,用来匹配html文件请求:

代码语言:javascript
复制
server {
  listen 2020;
  
  location / {
    root /data/test;
    index index.html;
  }
  
  location ~ \.html$ {
    return 200 'html文件请求拦截';
  }
}

请求localhost:2020,响应内容"html文件请求拦截"。这个例子很好的说明nginx内部会将初始页文件路径生成一个新的url,nginx内部重定向到这个新的url请求初始页文件。


index后面可以跟多个文件路径,当前一个文件不存在时,nginx会自动判断后面文件是否存在。下面使用一个例子来展示(/data/test目录下只有idnex.php文件):

代码语言:javascript
复制
server {
  listen 2020;
  
  location / {
    root /data/test;
    index index.html index.php;
  }
}

请求localhost:2020,nginx会首先判断文件/data/test/index.html是否存在,如果存在,就使用这个文件路径来生成新的文件url,然后nginx内部重定向到这个文件资源;如果不存在,就判断/data/test/index.php文件是否存在,如果不存在就返回403,如果存在,就使用这个文件路径来生成新的文件url,然后nginx内部重定向到这个文件资源。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-09-20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 路由匹配规则
    • 精确匹配(=)
      • 前缀匹配(^~)
        • 正则匹配(~ 和 ~*)
          • ~例子
          • ~*例子
        • 优先级
          • 优先级疑惑点
          • location常用的参数
            • root & alias
              • 最终指向的文件路径区别
              • 定义位置区别
              • 正则匹配时定义区别
            • proxy_pass
              • rewrite
                • index
                相关产品与服务
                负载均衡
                负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档