Nginx post转get问题分析
一、问题分析
现网配置:80端口判断不是https,则对url进行rewrite,跳转至443端口(永久重定向)。
server {
listen *:80 ;
server_name xxx.com;
if ($scheme != https ) {
rewrite ^(.*)$ https://${server_name}$1 permanent;
}
}
问题就在于:使用rewrite后,如果替换字符串以" http://"、" https://“或” $scheme"开头,则处理停止并将重定向返回给客户端(官方说法)。
重定向会生成新的子请求,无论原来是不是GET请求,新的重定向请求类型都是GET,请求体也会丢了,所以重定向请求会返回5xx,原请求返回301。
二、结论:
结合官方指令说明并测试:
①rewrite后的URL如果以" http://"、" https://“或” $scheme"开头,则默认生成子请求进行临时重定向302,生成重定向请求是GET类型。
②rewrite 指令结合redirect、permanent结尾使用,无论rewrite 后是不是以" http://"、" https://“或” $scheme"开头,都是重定向,生成子请求是GET类型。
三、解决方案:
(1)不使用rewrite,而使用location、proxy_pass,在nginx内部代理到443端口。
server {
listen 80;
location / {
if ($scheme != https ) {
proxy_pass https://10.19.1.82;
}
}
}
(2)使用rewrite,但不以" http://"、" https://“或” $scheme"开头,指令不结合redirect、permanent结尾使用,结合location、proxy_pass内部代理(这里只使用location,不用rewrite也可以得到同样的效果,可以理解rewrite为一种更灵活的location,因为都可以对URL进行处理、匹配、代理)。
server {
listen 80;
location /test {
rewrite ^/test/(.*)$ /$1 last;
}
location / {
if ($scheme != https ) {
proxy_pass https://10.19.1.82;
}
}
}
(3)使用return指令,因为return可以指定307状态码来重定向,状态码 307 与 302 之间的区别在于,当发送重定向请求的时候,307 状态码可以确保请求方法和消息主体不会发生变化。对于 GET 请求来说,两种情况没有区别。
server {
listen 80;
if ($scheme != https ) {
return 307 https://10.19.1.82$request_uri;
}
}
参考链接:rewrite模块
http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#rewrite