前端跨域問題總結

original_galaxy發表於2019-02-14

首先,瀏覽器為何要採用同源策略對跨域請求進行限制?

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





相關文章