在nginx中配置,使得訪問不帶www的網(wǎng)址自動重定向到帶www的域名。
http協(xié)議的重定向
在nginx官方文檔中有如下示例代碼:
server {
listen 80;
server_name example.com;
return 301 http://www.example.com$request_uri;
}
server {
listen 80;
server_name www.example.com;
...
}
對于return
字段,有兩點需要特別注意:
- 必須帶上協(xié)議頭,即
http://
- 必須帶上
$request_uri
參數(shù)
踩坑:return
字段必須帶上協(xié)議頭
經(jīng)踩坑,不帶上協(xié)議頭,訪問example.com
會重定向到example.com/www.example.com/www.example.com/www.example.com/www.example.com...
(url的長度達到8k+),最終出現(xiàn)414 Request-URI Too Large
錯誤。
我在進行測試時發(fā)現(xiàn)chrome會自動緩存301跳轉(zhuǎn),因此就算還原了nginx的配置文件,訪問example.com
仍然會重定向到剛才的超長網(wǎng)址上,一直都是414錯誤。有兩種方法可以解決301緩存的問題:
- 在瀏覽器的設(shè)置中清除緩存數(shù)據(jù)
- 使用隱私窗口進行測試(正確的打開方式?)
踩坑:必須帶上$request_uri
參數(shù)
full original request URI (with arguments)
nginx文檔中對該變量的描述比較簡單,通過搜索可以找到歷史版本的說明,(stackoverflow,博客園,新浪博客):
This variable is equal to the original request URI as received from the client including the args. It cannot be modified. Look at $uri for the post-rewrite/altered URI. Does not include host name. Example: "/foo/bar.php?arg=baz"
通過這個詳細的描述,可以了解$request_uri
參數(shù)表示從客戶端發(fā)送來的原生請求URI,包括參數(shù)。
經(jīng)踩坑,不帶上$request_uri
參數(shù),訪問example.com/abcd?123
會重定向到www.example.com
,即無論訪問任何子路徑,都會自動重定向到首頁。
https協(xié)議的重定向
參考http協(xié)議的重定向,我們添加了如下的配置:
server {
listen 443 ssl;
server_name example.com;
return 301 https://www.example.com$request_uri;
}
server {
listen 443 ssl;
server_name www.example.com;
...
}
重新加載nginx配置后,我們發(fā)現(xiàn) https://example.com 無法訪問,通過curl測試,返回下述錯誤信息:curl: (35) Server aborted the SSL handshake
,很明顯是ssl方面的問題。
而在配置前,https://example.com 和 https://www.example.com 都是可以正常訪問的,原始配置如下:
server {
listen 443 ssl;
server_name www.example.com;
server_name example.com;
ssl_certificate ssl/www.example.com.crt;
ssl_certificate_key ssl/www.example.com.key;
...
}
因此,我嘗試在重定向的配置中也添加ssl_certificate的配置信息:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate ssl/www.example.com.crt;
ssl_certificate_key ssl/www.example.com.key;
return 301 https://www.example.com$request_uri;
}
再次加載nginx配置后,發(fā)現(xiàn) https://example.com 正常訪問,并且可以自動重定向到 https://www.example.com 。
301還是302
- 301: 永久性轉(zhuǎn)移(Permanently Moved)
- 302: 暫時性轉(zhuǎn)移(Temporarily Moved)
共同點:二者都表示重定向,瀏覽器在獲取服務(wù)器的返回碼后會自動根據(jù)頭部的Location值跳轉(zhuǎn)到新的URL地址;
不同點:301表示舊地址被永久地移除了,已經(jīng)不可訪問;302表示舊地址還在,只是臨時進行跳轉(zhuǎn),后續(xù)還是訪問舊地址。
問題來了:什么情況下用301跳轉(zhuǎn)?什么情況下用302跳轉(zhuǎn)?
實際案例1,知乎:
- http://www.zhihu.com 跳轉(zhuǎn)到 https://www.zhihu.com 用的是301跳轉(zhuǎn)
- /za-js-sdk@latest/dist/zap.js 跳轉(zhuǎn)到 /za-js-sdk@2.4.5/dist/zap.js 用的是302跳轉(zhuǎn)
實際案例2,小米:
- http://mi.com/ 跳轉(zhuǎn)到 http://www.mi.com/ 用的是301跳轉(zhuǎn)
- http://www.mi.com/ 跳轉(zhuǎn)到 https://www.mi.com/ 用的是302跳轉(zhuǎn)
實際案例3,百度:
- http://tieba.baidu.com/ 跳轉(zhuǎn)到 https://tieba.baidu.com/index.html 用的是301跳轉(zhuǎn)
- http://baidu.com/ 跳轉(zhuǎn)到 https://www.baidu.com/ 用的是302跳轉(zhuǎn)
個人感覺,知乎的使用比較有代表性,從http到https做301永久跳轉(zhuǎn),表示知乎采用的是https的方式訪問,不會在回退到http的方式;而在獲取zap.js的時候,使用了302臨時跳轉(zhuǎn),跳轉(zhuǎn)到當前的版本,后續(xù)zap.js有更新的時候,也會302跳轉(zhuǎn)到更新后的地址。
注:文章中使用到的域名 example.com 為示例代碼,請根據(jù)項目需要自行修改。