在說跨域以前,咱們須要先了解下 同源策略。它是一個規範(Netscape 1995年提出),並無指定具體的使用範圍和實現方式。html
爲了保證使用者信息的安全,防止惡意網站篡改用戶數據,一些常見的Web技術都默認採用了同源策略(如Silverlight, Flash, XMLHttpRequest, Dom等)。前端
那如何判斷同源呢?git
咱們用一個表格來展現同源的判斷: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
Cookie,WebStorage(LocalStorage, SessionStorage),Cache(Application Cache, CacheStorage),Web DB(WebSql IndexDB)等都沒法共享json
沒法彼此操做各自的DOM(Iframe)後端
沒法發送Ajax請求api
其餘跨域
注意:若是兩個站點,具備相同的一級域名(如 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嵌入的站點都是咱們本身能夠控制的,那麼應直接使用 postMessage
來通訊。若是瀏覽器較舊,不支持 postMessage
,能夠考慮經過window.name來傳遞數據。
window.name 傳遞數據原理
首先在iframe訪問跨域的站點,這個站點,將數據寫入到window.name中。
而後主站點,修改iframe的location.href='about:blank' 或其餘不跨域的站點。
最後經過window.name獲取數據
這是由於同一個iframe的window.name是相互共享的。在現代瀏覽器中,該方式可能會失效,此時請使用 postMessage。
跨域使用字體文件,也會觸發攔截。這個的解決辦法和圖片跨域一致,後端設置CORS頭部便可。
這是咱們常常會遇到的跨域問題,因爲如今流行的開發模式,不少時候咱們都須要處理這類型的跨域。
如何判斷Ajax跨域
當咱們在訪問一個Ajax請求,控制檯出現以下錯誤時,咱們基本能夠判斷,是被跨域攔截了:
XMLHttpRequest cannot load xxxxx. No 'Access-Control-Allow-Origin' header is present on the requested resource.
不少時候,咱們的API和Web並不在一個站點上(多個域名),而咱們又必需要跨域訪問。這個時候咱們就須要想辦法實現跨域資源訪問。
如下,咱們就來看看如何實現跨域資源訪問:
開發模式的演進,致使咱們不少的應用都是跨域訪問。這個時候CORS規範也就應運而生了。使用它,咱們能夠直接對跨域資源進行訪問,瞭解更多,請參考CORS詳解。
該方式的核心是經過和後端API協商,看是否容許跨域訪問。對於知足某些條件的請求,會先發送一個預請求。簡單請求,也須要服務器容許跨域訪問。
最關鍵的的幾個響應頭以下:
注意:該方式由服務端設置,前端無需設置,也沒法設置。只要服務端處理好了,前端不須要作任何處理便可使用。
既然跨域有限制,那麼咱們能夠考慮將跨域變成同域,這樣不就沒有限制了麼?
以 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地址爲同域。
該方式利用Script請求資源不會觸發跨域限制這個特色來實現。JSON原理,請參考JSONP詳解。
注意:該方式須要先後端搭配,後端須要支持JSONP請求,前端須要採用JSONP的方式去請求數據。
注意2:該方式因爲實現原理限制,只能處理GET請求。
綜上,遇到跨域請求,就先去找後端啊。前端真的獨自搞不定啊。
跨域是項目開發中,很是常見的問題。就算是前端開發,也必定要理解跨域,瞭解跨域的處理方案。以便於可以真正的處理好開發任務(或許,這樣和後端交(Si)流(Bi)也更有底氣)。