閱讀目錄html
一:理解地址重寫 與 地址轉發的含義。node
地址重寫與地址轉發是兩個不一樣的概念。nginx
地址重寫 是爲了實現地址的標準化,好比咱們能夠在地址欄中中輸入 www.baidu.com. 咱們也能夠輸入 www.baidu.cn. 最後都會被重寫到 www.baidu.com 上。瀏覽器的地址欄也會顯示www.baidu.com。正則表達式
地址轉發:它是指在網絡數據傳輸過程當中數據分組到達路由器或橋接器後,該設備經過檢查分組地址並將數據轉發到最近的局域網的過程。後端
所以地址重寫和地址轉發有如下不一樣點:瀏覽器
1. 地址重寫會改變瀏覽器中的地址,使之變成重寫成瀏覽器最新的地址。而地址轉發他是不會改變瀏覽器的地址的。
2. 地址重寫會產生兩次請求,而地址轉發只會有一次請求。
3. 地址轉發通常發生在同一站點項目內部,而地址重寫且不受限制。
4. 地址轉發的速度比地址重定向快。安全
二:理解 Rewrite指令 使用服務器
該指令是經過正則表達式的使用來改變URI。能夠同時存在一個或多個指令。須要按照順序依次對URL進行匹配和處理。cookie
該指令能夠在server塊或location塊中配置,其基本語法結構以下:網絡
rewrite regex replacement [flag];
rewrite的含義:該指令是實現URL重寫的指令。
regex的含義:用於匹配URI的正則表達式。
replacement:將regex正則匹配到的內容替換成 replacement。
flag: flag標記。
flag有以下值:
last: 本條規則匹配完成後,繼續向下匹配新的location URI 規則。(不經常使用)
break: 本條規則匹配完成即終止,再也不匹配後面的任何規則(不經常使用)。
redirect: 返回302臨時重定向,瀏覽器地址會顯示跳轉新的URL地址。
permanent: 返回301永久重定向。瀏覽器地址會顯示跳轉新的URL地址。
好比以下列子:
rewrite ^/(.*) http://www.baidu.com/$1 permanent;
說明:
rewrite 爲固定關鍵字,表示開始進行rewrite匹配規則。
regex 爲 ^/(.*)。 這是一個正則表達式,匹配完整的域名和後面的路徑地址。
replacement就是 http://www.baidu.com/$1 這塊了,其中$1是取regex部分()裏面的內容。若是匹配成功後跳轉到的URL。
flag 就是 permanent,表明永久重定向的含義,即跳轉到 http://www.baidu.com/$1 地址上。
下面咱們來作個簡單的demo來模擬下:
1. 在咱們的測試項目下有個app.js. 代碼以下:
const Koa = require('koa'); const app = new Koa(); const router = require('koa-router')(); // 添加路由 router.get('/', ctx => { ctx.body = '<h1>歡迎光臨index page 頁面</h1>'; }); router.get('/home', ctx => { ctx.body = '<h1>歡迎光臨home頁面</h1>'; }); router.get('/404', ctx => { ctx.body = '<h1>404...</h1>' }); // 加載路由中間件 app.use(router.routes()); app.listen(3001, () => { console.log('server is running at http://localhost:3001'); });
而後在命令行中 運行 node app.js 後,運行,咱們就能夠在瀏覽器中 訪問 http://localhost:3001 就能夠訪問到咱們對應的頁面了。可是如今我想把該node項目
部署到我本地的nginx服務器上。nginx安裝請看我這篇文章 而後我想使用域名來訪問咱們的項目,所以咱們須要在咱們的nginx.conf中配置一下:
cd /usr/local/etc/nginx
而後使用命令:sudo open /usr/local/etc/nginx/nginx.conf -a 'sublime text' 命令打開 nginx.conf 配置以下:
worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen 8081; server_name localhost; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } server { listen 8088; server_name xxx.abc.com; location / { proxy_pass http://127.0.0.1:3001; rewrite ^/(.*) http://www.baidu.com permanent; } } }
如上代碼,我監聽端口號是8088,而後server_name 配置設置爲 xxx.abc.com, 而後當咱們訪問 http://xxx.abc.com:8088/的時候,會先反向代理到咱們的http://127.0.0.1:3001下的node對應的頁面上來,反向代理完成後,會使用 rewrite 重定向百度頁面去了。如上配置完成後,咱們須要重啓下nginx服務器;使用命令:
而後當咱們在瀏覽器訪問 http://xxx.abc.com:8088/ 的時候,會執行以下圖所示,它會先對 http://xxx.abc.com:8088/ 進行永久重定向(301), 而後會訪問百度(307),臨時重定向到百度頁面來,最終加載百度頁面的地址;以下演示所示:
可是若是我把 permanent 改爲 redirect 的話,好比nginx配置:rewrite ^/(.*) http://www.baidu.com redirect; 後,它就會變成302臨時重定向了。以下所示:
三:理解if指令
該指令用來支持條件判斷的,而且根據條件判斷結果來選擇不一樣的nginx的配置,咱們能夠在server塊或location塊中配置該指令,它的語法結構爲:
if (condition) { // .... }
condition 是布爾值 true/false的含義。
Rewrite 指令可用的全局變量以下:
1. $args: 該變量中存放了請求URL中的請求指令。好比 http://127.0.0.1:3001?arg1=value1&arg2=value2 中的
"arg1=value1&arg2=value2"。
2. $content_length: 該變量中存放了請求頭中的Content-length字段。
3. $content_type: 該變量中存放了請求頭中的 Content-type字段。
4. $document_root: 該變量中存放了針對當前請求的根路徑。
5. $document_uri: 該變量中存放了請求的當前URI, 可是不包括請求指令。好比 http://xxx.abc.com/home/1?arg1=value1&
arg2=value2; 中的 "/home/1"
6. $host: 變量中存放了請求的URL中的主機部分字段,好比http://xxx.abc.com:8080/home中的 xxx.abc.com.
7. $http_host: 該變量與$host惟一區別帶有端口號:好比上面的是 xxx.abc.com:8080
8. $http_user_agent: 變量中存放客戶端的代理信息。
9. $http_cookie, 該變量中存放客戶端的cookie信息。
10. $remote_addr 該變量中存放客戶端的地址。
11. $remote_port 該變量中存放了客戶端與服務器創建鏈接的端口號。
12. $remote_user 變量中存放客戶端的用戶名。
13. $request_body_file 變量中存放了發給後端服務器的本地文件資源的名稱
14. $request_method 變量中存放了客戶端的請求方式,好比 'GET'、'POST'等。
15. $request_filename 變量中存放了當前請求的資源文件的路徑名。
16. $request_uri 變量中存放了當前請求的URI,而且帶請求指令。
17. $query_string 和變量$args含義同樣。
18. $scheme 變量中存放了客戶端請求使用的協議,好比 'http', 'https'等。
19. $server_protocol 變量中存放了客戶端請求協議的版本, 好比 'HTTP/1.0'、'HTTP/1.1' 等。
..... 等等
正則表達式的基本語法:
1. 對變量進行匹配
'~' 表示匹配過程當中對大小寫敏感。
'~*' 表示匹配過程當中對大小寫不敏感。
'!~' 若是 '~' 匹配失敗時,那麼該條件就爲true。
'!~*' 若是 '~*' 匹配失敗時,那麼該條件就爲true。
好比以下:
if ($http_user_agent ~ MSIE) { // 代碼的含義:$http_user_agent值中是否含有 MSIE 字符串,若是包含爲true,不然爲false }
2. 判斷請求的文件是否存在
'-f' 若是請求的文件存在,那麼該條件爲true。
'!-f' 若是該文件的目錄存在,該文件不存在,那麼返回true。若是該文件和目錄都不存在,則爲false。
若是請求的目錄不存在,請求的文件存在,也爲false。
if (-f $request_filename) { // 判斷請求的文件是否存在 } if (!-f $request_filename) { // 判斷請求的文件是否不存在 }
3. 判斷請求的目錄是否存在使用 '-d' 和 '!-d'
使用 '-d',若是請求的目錄存在,則返回true。不然返回false。
使用 '!-d', 若是請求的目錄不存在,可是該請求的上級目錄存在,則返回true。若是該上級目錄不存在,則返回false.... 等等其餘一些語法,很少介紹。
如今咱們使用if指令來對nginx加一些判斷;好比說咱們訪問http://xxx.abc.com:8080/home時候,若是$host = 'xxx.abc.com' 的時候,就作重定向跳轉,nginx配置代碼以下:
server { listen 8088; server_name xxx.abc.com; location / { proxy_pass http://127.0.0.1:3001; if ($host = 'xxx.abc.com') { rewrite ^/(.*) http://www.cnblogs.com redirect; } } }
nginx 如上配置,若是咱們訪問 http://xxx.abc.com:8088 的時候,它就會重定向到 http://www.cnblogs.com 來了。
好比更多的判斷,好比若是用戶代理是手機訪問的話,直接跳轉到某個頁面去,也可使用if判斷。好比以下:
if ( $http_user_agent ~* "(Android)|(iPhone)|(Mobile)|(WAP)|(UCWEB)" ){ rewrite ^/$ http://www.cnblogs.com permanent; }
四:理解防盜鏈及nginx配置
什麼是防盜鏈?盜鏈能夠理解盜圖連接,也就是說把別人的圖片偷過來用在本身的服務器上,那麼防盜鏈能夠理解爲防止其餘人把個人圖片盜取過去。
防盜鏈的實現原理:客戶端向服務器端請求資源時,爲了減小網絡帶寬,提升響應時間,服務器通常不會一次將全部資源完整地傳回客戶端。好比請求一個網頁時,首先會傳回該網頁的文本內容,當客戶端瀏覽器在解析文本的過程當中發現有圖片存在時,會再次向服務器發起對該圖片資源的請求,服務器將存儲的圖片資源再發送給客戶端。可是若是這個圖片是連接到其餘站點的服務器上去了呢,好比在我項目中,我引用了的是淘寶中的一張圖片的話,那麼當咱們網站從新加載的時候,就會請求淘寶的服務器,那麼這就頗有可能形成淘寶服務器負擔。所以這個就是盜鏈行爲。所以咱們要實現防盜鏈。
實現防盜鏈:使用http協議中請求頭部的Referer頭域來判斷當前訪問的網頁或文件的源地址。經過該頭域的值,咱們能夠檢測訪問目標資源的源地址。若是目標源地址不是咱們本身站內的URL的話,那麼這種狀況下,咱們採起阻止措施,實現防盜鏈。可是注意的是:Referer頭域中的值是能夠被更改的。所以該方法也不能徹底安全阻止防盜鏈。
使用Nginx服務器的Rewrite功能實現防盜鏈。
Nginx中有一個指令 valid_referers. 該指令能夠用來獲取 Referer 頭域中的值,而且根據該值的狀況給 Nginx全局變量 $invalid_referer 賦值。若是Referer頭域中沒有符合 valid_referers指令的值的話,$invalid_referer變量將會賦值爲1. valid_referers 指令基本語法以下:
valid_referers none | blocked | server_names | string
none: 檢測Referer頭域不存在的狀況。
blocked: 檢測Referer頭域的值被防火牆或者代理服務器刪除或假裝的狀況。那麼在這種狀況下,該頭域的值不以"http://" 或 "https://" 開頭。
server_names: 設置一個或多個URL,檢測Referer頭域的值是不是URL中的某個。
所以咱們有了 valid_referers指令和$invalid_referer變量的話,咱們就能夠經過 Rewrite功能來實現防盜鏈。
下面咱們介紹兩種方案:第一:根據請求資源的類型。第二:根據請求目錄。
1. 根據請求文件類型實現防盜鏈配置實列以下:
server { listen 8080; server_name xxx.abc.com location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip)$ { valid_referers none blocked www.xxx.com www.yyy.com *.baidu.com *.tabobao.com; if ($invalid_referer) { rewrite ^/ http://www.xxx.com/images/forbidden.png; } } }
如上基本配置,當有網絡鏈接對以 gif、jpg、png爲後綴的圖片資源時候、當有以swf、flv爲後綴的媒體資源時、或以 rar、zip爲後綴的壓縮資源發起請求時,若是檢測到Referer頭域中沒有符合 valid_referers指令的話,那麼說明不是本站的資源請求。
location ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip)$ 該配置的含義是 設置防盜鏈的文件類型。
valid_referers none blocked www.xxx.com www.yyy.com *.baidu.com *.tabobao.com; 能夠理解爲白名單,容許文件鏈出的域名白名單,若是請求的資源文件不是以這些域名開頭的話,就說明請求的資源文件不是該域下的請求,所以能夠判斷它是盜鏈。所以若是不是該域下的請求,就會使用 Rewrite進行重定向到 http://www.xxx.com/images/forbidden.png 這個圖片,好比這張圖片是一個x或其餘的標識,而後其餘的網站就訪問不了你這個圖片哦。
2. 根據請求目錄實現防盜鏈的配置實列以下:
server { listen 8080; server_name xxx.abc.com location /file/ { root /server/file/; valid_referers none blocked www.xxx.com www.yyy.com *.baidu.com *.tabobao.com; if ($invalid_referer) { rewrite ^/ http://www.xxx.com/images/forbidden.png; } } }