昨天写了篇 nginx rewrite 与 proxypass 的问题分享,最初的配置是运维同学写的,细想了下发现 rewrite 与 proxypass 共用有点奇怪,感觉仍然有一些问题没有分析清楚,今天就再具体细致地分析一下。
我们对比下同时使用 rewrite 与 proxy_pass 与单独使用其中一个的情况下,服务端获取到的 url 的表现。获取 url 的代码如下:
location /qz/ {
#rewrite ^/qz/websocket/(.*)$ /websocket/$1 break ;
proxy_pass http://websocketqz/;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'Upgrade';
}
可见,这里的 rewrite 是注释掉了的。
浏览器请求:http://localhost:8888/qz/websocket/,服务器输出信息为:
before request method is:GET req uri is:/websocket/-[]
nginx日志为:
127.0.0.1 - - [08/Nov/2019:11:32:12 +0800] "GET /qz/websocket/ HTTP/1.1" 404 13 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
可以看到最后经过 proxy_pass 后进入 websocket 服务的路径为http://websocketqz/websocket/
浏览器请求:http://localhost:8888/qz/websocket,服务器输出信息为:
before request method is:GET req uri is:/websocket-[]
nginx日志为:
127.0.0.1 - - [08/Nov/2019:11:32:06 +0800] "GET /qz/websocket HTTP/1.1" 404 13 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
这种情况下由于/qz/websocket 的/qz/部分完全匹配了 location,则不会进行添加/进行 301 跳转的情况,会将websocket这一串添加到proxy_pass路径后面。
location /qz/websocket {
#rewrite ^/qz/websocket/(.*)$ /websocket/$1 break ;
proxy_pass http://websocketqz/;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'Upgrade';
}
before request method is:GET req uri is://-[]
127.0.0.1 - - [08/Nov/2019:11:26:53 +0800] "GET /qz/websocket/ HTTP/1.1" 404 13 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
也就是说经过 proxypass 后的请求为http://websocketqz//,这就是proxypass发挥作用了,与location匹配多出的部分是/,这个会被加在proxy_pass的后面。
before request method is:GET req uri is:/-[]
127.0.0.1 - - [08/Nov/2019:11:26:55 +0800] "GET /qz/websocket HTTP/1.1" 404 13 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
location /qz/websocket/ {
#rewrite ^/qz/websocket/(.*)$ /websocket/$1 break ;
proxy_pass http://websocketqz/;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'Upgrade';
}
before request method is:GET req uri is://-[]
before request method is:GET req uri is:/-[]
127.0.0.1 - - [08/Nov/2019:11:20:41 +0800] "GET /qz/websocket HTTP/1.1" 301 185 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
127.0.0.1 - - [08/Nov/2019:11:20:41 +0800] "GET /qz/websocket/ HTTP/1.1" 404 13 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
如果请求换成 post 方式,服务端输出为:
before request method is:GET req uri is:/-[]
nginx 日志为:
127.0.0.1 - - [08/Nov/2019:11:20:54 +0800] "POST /qz/websocket HTTP/1.1" 301 185 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
127.0.0.1 - - [08/Nov/2019:11:20:54 +0800] "GET /qz/websocket/ HTTP/1.1" 404 13 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.87 Safari/537.36"
可以看到这里会有一次在/qz/websocket后加/然后进行301 重定向的行为,关于这点上篇中已经重点提到过,需要注意的是这次重定向会将原本的 POST 请求转换成 GET 请求。
看了上面的对比,与上一篇的配置和表现和对比,有没有发现点什么问题?
我们不妨把rewrite规则放开,改成如下配置:
location /qz/ {
rewrite ^/qz/websocket/(.*)$ /websocket/$1 break ;
proxy_pass http://websocketqz/;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header REMOTE-HOST $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'Upgrade';
}
在其他情况下把rewrite放开,也基本上没什么异样,情况与去掉rewrite规则时一模一样。可见,在这里rewrite基本是不需要的。proxy_pass已经满足需求了。