這些年咱們處理過的跨域

同源策略

在說跨域以前,咱們須要先了解下 同源策略。它是一個規範(Netscape 1995年提出),並無指定具體的使用範圍和實現方式。html

爲了保證使用者信息的安全,防止惡意網站篡改用戶數據,一些常見的Web技術都默認採用了同源策略(如Silverlight, Flash, XMLHttpRequest, Dom等)。前端

那如何判斷同源呢?git

  1. 相同的協議
  2. 相同的域名
  3. 相同的的端口號

咱們用一個表格來展現同源的判斷:github

URL1 URL2 是否同源 分析
http://www.a.com https://www.a.com 不一樣源 協議不一致
http://www.a.com http://www.b.com 不一樣源 域名不一致
http://www.a.com http://www.a.com:8080 不一樣源 端口不一致
http://www.a.com http://test.a.com 不一樣源 域名不一致
http://www.a.com http://www.a.com/test 同源 判斷同源和path無關
http://www.a.com http://www.a.com:80 同源 不帶端口訪問時,默認是80

若是不是同源會有哪些使用限制呢?ajax

  1. Cookie,WebStorage(LocalStorage, SessionStorage),Cache(Application Cache, CacheStorage),Web DB(WebSql IndexDB)等都沒法共享json

  2. 沒法彼此操做各自的DOM(Iframe)後端

  3. 沒法發送Ajax請求api

  4. 其餘跨域

注意:若是兩個站點,具備相同的一級域名(如 www.a.com, test.a.com,一級域名都是a.com),那麼能夠經過各自設置document.domain='a.com' 來共享Cookie。瀏覽器

注意2:若是是iframe非同源,雖然不能操做dom,可是能操做location.href。

什麼是跨域?

經過以上內容,咱們瞭解到了什麼是同源策略,以及怎麼判斷同源。那麼與之相反,若是不知足同源,則就是跨域。

在瀏覽器上,若是訪問跨域資源,將會有諸多限制(爲了安全),參考上面的同源限制。

注意:跨域限制是瀏覽器的機制,若是直接在服務端請求,是不會觸發跨域限制的。

那些咱們遇到的跨域

一、圖片跨域

對於圖片來講,大部分場景是不須要處理跨域限制的,由於通常來講,圖片沒有跨域限制。

在也有例外,若是在 Canvas 中操做跨域的圖片,那麼就會觸發跨域限制。解決辦法是在返回圖片的時候,添加 Access-Control-Allow-Origin: orign | '*' 來容許跨域。

二、Iframe跨域

這個也不太常見,若是網站自己和iframe嵌入的站點都是咱們本身能夠控制的,那麼應直接使用 postMessage 來通訊。若是瀏覽器較舊,不支持 postMessage ,能夠考慮經過window.name來傳遞數據。

window.name 傳遞數據原理

首先在iframe訪問跨域的站點,這個站點,將數據寫入到window.name中。

而後主站點,修改iframe的location.href='about:blank' 或其餘不跨域的站點。

最後經過window.name獲取數據

這是由於同一個iframe的window.name是相互共享的。在現代瀏覽器中,該方式可能會失效,此時請使用 postMessage。

三、字體跨域

跨域使用字體文件,也會觸發攔截。這個的解決辦法和圖片跨域一致,後端設置CORS頭部便可。

四、Ajax跨域

這是咱們常常會遇到的跨域問題,因爲如今流行的開發模式,不少時候咱們都須要處理這類型的跨域。

如何判斷Ajax跨域

當咱們在訪問一個Ajax請求,控制檯出現以下錯誤時,咱們基本能夠判斷,是被跨域攔截了:

XMLHttpRequest cannot load xxxxx. No 'Access-Control-Allow-Origin' header is present on the requested resource.

不少時候,咱們的API和Web並不在一個站點上(多個域名),而咱們又必需要跨域訪問。這個時候咱們就須要想辦法實現跨域資源訪問

如下,咱們就來看看如何實現跨域資源訪問:

CORS(跨域資源訪問)- 標準作法,強烈推薦

開發模式的演進,致使咱們不少的應用都是跨域訪問。這個時候CORS規範也就應運而生了。使用它,咱們能夠直接對跨域資源進行訪問,瞭解更多,請參考CORS詳解

該方式的核心是經過和後端API協商,看是否容許跨域訪問。對於知足某些條件的請求,會先發送一個預請求。簡單請求,也須要服務器容許跨域訪問。

最關鍵的的幾個響應頭以下:

  1. Access-Control-Allow-Origin: origin | '*' 容許某個指定的域訪問,*表示不限制域。
  2. Access-Control-Allow-Methods: 'GET,POST,PUT,DELETE' 容許哪些類型的請求
  3. Access-Control-Allow-Headers: 'x-token' 容許的自定義Header。

注意:該方式由服務端設置,前端無需設置,也沒法設置。只要服務端處理好了,前端不須要作任何處理便可使用。

反向代理(將跨域代理爲同域,繞過)

既然跨域有限制,那麼咱們能夠考慮將跨域變成同域,這樣不就沒有限制了麼?

Nginx 爲例,咱們只須要將特定路徑的請求轉發給真正的後端API便可:

server {
    listen 8101;
    root /dist;
    index index.html;

    location ~* \.(eot|ttf|woff|woff2)$ {
        add_header x-server $server_addr;
        add_header Access-Control-Allow-Origin '*';
    }
    
    location ^~ /api/v1 {
        proxy_pass http://apis.xxx.com/api/v1;
    }
}

注意:該方式須要在部署的時候作處理,前端須要修改請求api的地址爲同域。

服務端轉發(經過不跨域的請求跨域API,繞過)

該方式,經過請求不跨域的api,而後在api中再呼叫真實的跨域api,因爲是服務端請求,因此也就避開了跨域問題。總體看來,這種方式有點畫蛇添足,不過若是把這個轉發由統一的程序進行處理,仍是挺不錯的。

注意:該方式在後端API中處理,前端須要修改請求api地址爲同域。

JSONP(利用script無跨域限制,繞過)

該方式利用Script請求資源不會觸發跨域限制這個特色來實現。JSON原理,請參考JSONP詳解

注意:該方式須要先後端搭配,後端須要支持JSONP請求,前端須要採用JSONP的方式去請求數據。

注意2:該方式因爲實現原理限制,只能處理GET請求。


綜上,遇到跨域請求,就先去找後端啊。前端真的獨自搞不定啊。

總結

跨域是項目開發中,很是常見的問題。就算是前端開發,也必定要理解跨域,瞭解跨域的處理方案。以便於可以真正的處理好開發任務(或許,這樣和後端交(Si)流(Bi)也更有底氣)。

相關文章
相關標籤/搜索