背景
本次分享来自于一次阿里云域名备案要求,需要给我们的原来没有配置”正经“首页的api域名增加一个首页,本来应该是一个很简单的需求,接到需求的时候就想到只需要简单nginx配置一下就行~~~没想到。。。请看下面👇
现实
这次需要配置的域名对应的GO服务路由其实很简单。。也许就是因为他的简单。。。所以才有了这次不那么简单的nginx配置吧
下面就是全部go的配置
beego.Get("/", func(ctx *context.Context) {
//ctx.Redirect( 301,"https://www.m***ji.com")//本来是想做个重定向的,但这个样好像就不是我们想要的满足备案要求了,所以最后就没改了。
retData := util.RetData{Code: 200, Msg: "Hello"}
ctx.Output.JSON(retData, true, false)
})
beego.Router("/api/v1/xx1", &controllers.XX1Controller{}, "*:Run")
beego.Router("/api/v1/xx2", &controllers.XX2Controller{}, "*:Run")
beego.Router("/:url([a-zA-z0-9]{6,})", &controllers.xx3Controller{}, "*:Run")
beego.Get("/*", func(ctx *context.Context) {
retData := util.RetData{Code: 404, Msg: "Not Found"}
ctx.Output.JSON(retData, true, false)
})复制
实现
随手而来的是这样的
server {
listen 80;
server_name test.xxx.pub;
root /home/test/projects/xx/;
index index.html index.html;
access_log /home/test/projects/xx/access.log;
error_log /home/test/projects/xx/error.log;
location = / {
alias /home/test/projects/xx/;
index index.html index.html;
}
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8099;
}
}复制
请求网页返回结果
从图片可以看出返回了404应该是进入到了go服务里面了,匹配到了上面相应的路由
beego.Get("/*", func(ctx *context.Context) {
retData := util.RetData{Code: 404, Msg: "Not Found"}
ctx.Output.JSON(retData, true, false)
})复制
这样看来nginx配置应该是有问题
于是为了验证 ”location = “是有被使用的,所以在后面加上了return 404这个状态码
server {
listen 80;
server_name test.xx.pub;
root /home/test/projects/xx/;
index index.html index.html;
access_log /home/test/projects/xx/access.log;
error_log /home/test/projects/xx/error.log;
location = / {
alias /home/test/projects/xx/;
index index.html index.html;
return 404;
}
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8099;
}
}复制
页面返回nginx的404状态页,也就是说请求是有被 ”location = “ 匹配到的,那为什么上面没有增加return 404这个状态码的请求返回的值进到了go项目呢
我们快进一下,修改为下面这两段代码,打印一下请求的uri,或许能有一些线索
第一次先修改这增加返回uri
location = / {
alias /home/test/projects/xx/;
index index.html index.html;
default_type text/html;
return 200 $uri;
}
下一次测试修改这段
location / {
default_type text/html;
return 200 $uri;
}复制
第一段配置返回值 uri 是斜杠 /
,第二段配置返回值同样是/
。看到这里也就不难理解刚才代码为什么已经使用了 location =
但还是进到go服务里面而不是返回我们想要它返回index.html路径了,因为它匹配完 location =
后 还匹配到了 location
,从而导致和我们想要的结果不一致。
当然,这个过程我们还尝试了很多种不同的写法,但都没办法达到我们想的结果,最后使用rewrite解决了我们的问题。
server {
listen 80;
server_name test.xx.pub;
access_log /home/test/projects/xx/access.log;
error_log /home/test/projects/xx/error.log;
if ($uri = '/') {
rewrite .* http://test.xx.pub/index.html? permanent;#这里增加 ? 是为了让请求后面不带参数,因为这只是首页
}
location = /index.html {
root /home/test/projects/xx/;
index index.html;
}
location / {
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8099;
}
}复制
号外(内容来源互联网)
location 匹配简介
从功能看,rewrite 和 location 似乎很像,都能实现跳转,主要区别在于 rewrite 是在同一域名内更改获取资源的路径,而 location 是对一类路径做控制访问或反向代理,还可以 proxy_pass 到其他机器。
匹配规则格式
①精准匹配 location = {...}
②一般匹配 location {...}
③正则匹配 location ~ {...}
常用的匹配规则
= :进行普通字符精确匹配,也就是完全匹配。
^~ :表示普通字符匹配。使用前缀匹配。如果匹配成功,则不再匹配其它 location。
~ :区分大小写的匹配。
~* :不区分大小写的匹配。
!~ :区分大小写的匹配取非。
!~* :不区分大小写的匹配取非。
location = / {
#规则A
}
location = /aa {
#规则B
}
location ^~ /aa/ {
#规则C
}
location ~ \.(gif|jpg|png)$ {
#规则D
}
location ~* \.png$ {
#规则E
}
location !~ \.html$ {
#规则F
}
location !~* \.html$ {
#规则G
}
location / {
#规则H
}复制
匹配的优先级
首先精确匹配 = 其次前缀匹配 ^~ 再其次是按文件中顺序的正则匹配 或* 然后匹配不带任何修饰的前缀匹配(一般匹配) 最后是交给 通用匹配
示例
(1)location = / {}
=为精确匹配 / ,主机名后面不能带任何字符串,比如访问 / 和 /data,则 / 匹配,/data 不匹配
再比如 location = /abc,则只匹配/abc ,/abc/或 /abcd不匹配。若 location /abc,则即匹配/abc 、/abcd/ 同时也匹配 /abc/。
(2)location / {}
因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求 比如访问 / 和 /data, 则 / 匹配, /data 也匹配,
但若后面是正则表达式会和最长字符串优先匹配(最长匹配)
(3)location /documents/ {}
匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索其它 location
只有其它 location后面的正则表达式没有匹配到时,才会采用这一条
(4)location /documents/abc {}
匹配任何以 /documents/abc 开头的地址,匹配符合以后,还要继续往下搜索其它 location
只有其它 location后面的正则表达式没有匹配到时,才会采用这一条
(5)location ^~ /images/ {}
匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条
(6)location ~* \.(gif|jpg|jpeg)$ {}
匹配所有以 gif、jpg或jpeg 结尾的请求
然而,所有请求 /images/ 下的图片会被 location ^~ /images/ 处理,因为 ^~ 的优先级更高,所以到达不了这一条正则
(7)location /images/abc {}
最长字符匹配到 /images/abc,优先级最低,继续往下搜索其它 location,会发现 ^~ 和 ~ 存在
(8)location ~ /images/abc {}
匹配以/images/abc 开头的,优先级次之,只有去掉 location ^~ /images/ 才会采用这一条
(9)location /images/abc/1.html {}
匹配/images/abc/1.html 文件,如果和正则 ~ /images/abc/1.html 相比,正则优先级更高复制