基于全球的網絡安全,現在瀏覽器基本都將默認的HTTP站點標識為不安全,很多站點都將HTTP網站添加SSL證書,切換至HTTPS加密協議。
Nginx作為高性能的HTTP和反向代理web服務,一般作為服務入口提供負載均衡和流量分發,因此我們在Nginx上添加SSL證書,實現HTTPS訪問;同時為保證用戶無感知,需要配置HTTP默認跳轉HTTPS。
下面我們來解析下泛域名下的http默認跳轉https。
rewrite跳轉
server{
listen 80;
server_name *.test.cn;
rewrite ^(.*)$ https://$server_name$1 permanent;
}
此時瀏覽器訪問報錯:
其實此時使用rewrite跳轉在單域名是沒有問題,但是在多域名或泛域名下是有問題的,我們此時使用在nginx安裝echo-nginx-modulem模塊以調試(模塊安裝忽略)。
調試過程
1.依次打印nginx內置變量server_name,host,http_host
server{
listen 80;
server_name *.test.cn;
location / {
default_type 'text/plain';
echo $server_name;
echo $host;
echo $http_host;
}
}
瀏覽器訪問:
2.錯誤分析
從變量打印來看:
server_name值為*.test.cn
host值為www.test.cn
http_host值為www.test.cn
此時雖然我們輸入域名為www.test.cn,但實際rewrite的url為:https://*.test.cn,因此訪問報錯。
注意:如果你的nginx的域名為"server_name a.test.cn *.test.cn www.test.cn",則變量server_name的值為a.test.cn,即匹配的是配置文件中server_name第一個域名。
3.解決方式
根據變量值,我們需要更改rewrite后的url為:
rewrite ^(.*)$ https://$host$1 permanent;
或
rewrite ^(.*)$ https://$http_host$1 permanent;
return
return除了支持直接跟狀態碼,還可以跟字符串或者url鏈接,用于返回字符串或url鏈接。
http默認跳轉為https配置如下:
server{
listen 80;
server_name *.test.cn;
return 301 https://$http_host$request_uri;
}
總結
return和rewrite雖然都實現了跳轉,但是是有區別的:
1.return 指令簡單高效,建議盡量使用 return,而不是 rewrite;
2.return 指令告訴 Nginx 停止處理請求,直接返回 301 (Moved Permanently) 代碼并跳轉重寫后的地址;
3.rewrite指定并不會立即結束Nginx的處理流程,會根據重寫后的地址繼續匹配相應的location,除非使用break結束。
擴展
如果使用Nginx+Lua,你會發現在整個Nginx的訪問流程中,return指令處于rewrite階段,而rewrite指令處于access階段,因此return的優先級是高于ngx_limit_req訪問頻率限制的。