首先,瀏覽器為何要採用同源策略對跨域請求進行限制?
CSRF(Cross-site request forgery),中文名稱:跨站請求偽造。限制跨域是指限制兩個網站相互讀寫對方的資料,合理性顯而易見。可以這麼理解CSRF攻擊:攻擊者盜用了你的身份,以你的名義傳送惡意請求。CSRF能夠做的事情包括:以你名義傳送郵件,發訊息,盜取你的賬號,甚至於購買商品,虛擬貨幣轉賬......造成的問題包括:個人隱私洩露以及財產安全。
更多歷史背景和實際案例可參照知乎連結:
https://www.zhihu.com/question/26379635
其次,常用解決方案:
前端專案整合nodejs - request模組
本地localhost啟動一nodejs服務,新增一路由,程式碼舉例如下:
router.get('/sina', function(req, res, next) {
console.log('req.headers: ', req.headers);
request('http://sina.com', function(error, response, data) {
console.log('error: ', error);
console.log('response: ', response.statusCode);
console.log('typeof(data): ', typeof(data));
console.log('data: ', data.length);
res.send({body: 'body'})
})
})複製程式碼
此場景下,http://sina.com是可以被成功訪問的。個人理解就是此處是從一本地伺服器訪問sina.com
,相當於規避掉了瀏覽器的跨域訪問限制。且前端專案整合了nodejs後,可在nodejs中去管理維護後端介面的呼叫,同時可在Linux伺服器上採用PM2工具,單獨部署專案。
被呼叫方 - NGINX解決方案
虛擬主機:多個域名指向同一個伺服器,伺服器根據不同域名,將請求轉向不同應用伺服器,看上去好像有多個主機,實際上只有一個主機。
先進行被呼叫方虛擬主機的配置:
先進行host的配置:
開啟windows下的hosts檔案,編輯,先對映一個本地域名:
127.0.0.1 b.com複製程式碼
用b.com表示被呼叫方的域名。
然後開啟nginx下的conf目錄,新建vhost資料夾,用於存放虛擬主機的配置檔案,實際工作中一般就採用這種習慣;開啟nginx.conf檔案,在最後一行新增程式碼
include vhost/*.conf;複製程式碼
要nginx載入這個目錄下面所有.conf結尾的檔案。
在vhost中新建b.com.conf檔案,用nginx的語法在其中增加一節點:
作用是,將所有請求轉到localhost:8080,監聽80埠,命名為b.com。
在nginx-1.11.5目錄下開啟命令列視窗:
先執行nginx.exe -t
,測試一下配置檔案,測試成功後執行start nginx.exe
啟動nginx,啟動成功後進行測試:
將原來的訪問url開頭的localhost:8080改為b.com,執行後若依然能正常訪問,代表測試成功,說明虛擬主機配置完成了。
因為這次是要在nginx上實現filter的功能,則先將原來的後臺服務端的filter功能刪除掉,
將註冊filter的配置註釋掉:
將下面的邏輯移到nginx中:
其中3個為固定值,另外兩個由請求的頭來決定,
改為:
將預檢命令的邏輯處理也新增其中,在nginx中直接返回,就不需要轉到應用伺服器了。
執行nginx.exe -t
,測試一下配置檔案。
執行nginx.exe -s reload
對nginx進行重新載入。
原來html中base url是通過localhost:8080直接訪問的被呼叫方的應用伺服器,現在將localhost:8080改為b.com,即變成了html中去訪問被呼叫方的nginx http伺服器了。
傳送的cookie是被呼叫方的域名的cookie。在b.com下新增document.cookie='cookie1=xxx'
。
被呼叫方 - apache解決方案
先執行nginx.exe -s stop
將nginx停止掉,然後重新整理b.com的請求,請求失敗,說明nginx被停掉了。接下來進行apache的配置:
與nginx一樣,我們先進行虛擬主機的配置,進入Apache24/conf目錄下,開啟httpd.conf檔案,
先開啟虛擬主機的相關配置,搜尋vhost,將LoadModule...mod_vhost_alias.so
註釋開啟,
將配置檔案Include conf/extra/httpd-vhosts.conf
註釋也開啟,儲存httpd.conf。
找到對應的虛擬主機配置檔案,即conf/extra/httpd-vhosts.conf
,開啟,檔案中的每一個節點就是一個虛擬主機,將最後一個節點的程式碼複製一份並新增到最後,刪掉無用的前兩行,ServerName改為b.com,日誌改為b.com-error.log...
。在最後一行增加一個代理,讓它把我們的請求轉發過去,
ProxyPass / http://localhost:8080/
然後將此配置檔案儲存。因為此處使用了Proxy模組,所以需將檔案中Proxy模組也開啟,搜一下,將140行
LoadModule proxy_module modules/mod_proxy.so複製程式碼
開啟,還需要把149行的
LoadModule proxy_http_module modules/mod_proxy_http.so複製程式碼
開啟,儲存檔案。
鍵入Apache/bin目錄,雙擊httpd.exe,彈出視窗,Apache啟動成功,重新整理下b.com的請求,此時b.com可正常訪問了,表示虛擬主機配置成功了。
來測試一下,重新整理下測試用例,看到為全部失敗,接下來需要在Apache上配置下響應頭,
增加支援跨域的響應頭:
繼續編輯httpd-vhosts.conf檔案,在ProxyPass下增加程式碼:
Apache的配置比較複雜:
需要將httpd.conf中Headers和Rewrite模組開啟:
搜尋headers,將118行開啟
LoadModule headers_module modules/mod_headers.so複製程式碼
搜尋rewrite,將158行開啟
LoadModule rewrite_module modules/mod_rewrite.so複製程式碼
儲存修改後的兩個檔案。
將Apache關掉,雙擊重啟,重新整理測試用例,此時測試用例全部成功,表示此時的Apache支援跨域了,Apache的配置到此結束。
被呼叫方 - Spring框架解決方案
之前的方案都和框架無關,比如filter,是每個web應用都有的。如果採用了Spring框架,那麼解決方案就變得簡單起來,增加相應註解即可,請求也不需要再經過中間的http伺服器了。
所以,首先將html中的base url b.com改回為localhost:8080,修改伺服器後臺程式碼,在TestController中增加註解,
@CrossOrogin
public class TestController {
複製程式碼
儲存,
再次重新整理測試用例,可以看到,測試用例全部通過。
@CrossOrogin
可以加在類上面,也可以加在具體的方法上面。加在類上即代表此類的所有方法都支援跨域;它還可以進行一些額外的配置,但一般場景是不需要額外配置的。
呼叫方解決跨域 - 隱藏跨域 - nginx配置
當你無法修改被呼叫方的時候,就要在呼叫方做文章。請求是經由呼叫方的http伺服器的反向代理,轉發到被呼叫方的伺服器的,在瀏覽器上面,看不到任何的跨域請求。
那麼,什麼是反向代理呢?
簡單來說,就是你訪問同一個域名的兩個不同url,它們最後會去到兩個不同的伺服器,我們通過接下來的測試來理解這個概念:
先看一下反向代理在nginx上是怎樣配置的:
配置之前,先把測試環境還原成不支援跨域呼叫,
把註解@CrossOrigin
刪除掉:
接下來,在
C:\Windows\System32\drivers\etc\hosts
檔案中增加一個host,
將原127.0.0.1 b.com改為
127.0.0.1 b.com a.com複製程式碼
用a.com表示呼叫方的虛擬主機。
然後,在nginx-1.11.5\conf\vhost中新建配置檔案a.com.conf
域名為a.com,將所有請求轉發到81埠,
加一個代理,把我們要呼叫的伺服器的地址代理成ajaxserver
將html中的base url改為/ajaxserver
。
執行start nginx.exe
啟動nginx
執行nginx -s reload
重新載入配置,訪問a.com,可以看到3個成功,但getCookie失敗了,
是因為新的域名裡沒有cookie的資訊,在a.com下新增document.cookie="cookie1=xxx"
再次重新整理,測試用例全部成功,跨域問題得到了解決。
看一下這種隱藏跨域與之前的支援跨域最大不同是什麼?
就是我們呼叫的base url。
隱藏跨域下面呼叫的url都是本域的,所以base url處為相對地址,
而之前支援跨域裡面,base url處寫的必須是絕對地址,這就是最大的不同。
瀏覽器看到都是相對地址,都是同一個域的地址,所以不會有任何跨域問題。
呼叫方解決跨域 - 隱藏跨域 - Apache配置
Apache反向代理配置:
配置的目的就是增加一個虛擬主機,在虛擬主機中把跨域請求做一個代理,
找到Apache的虛擬主機配置檔案conf/extra/httpd-vhosts.conf
增加一個節點:
將base url改為ajaxserverapache
,
儲存。將nginx.exe -s stop
停掉,啟動Apache服務,
執行a.com,測試成功,
且發現Request URL為http://a.com/ajaxserverapache/getCookie
Apache反向代理配置完成。
注:以上文章部分整理自慕課網教學視訊:
https://www.imooc.com/video/16591
https://www.imooc.com/video/16592