1. 程式人生 > >跨域問題(前端面試最常問)

跨域問題(前端面試最常問)

為什麼要跨域?

跨域問題是瀏覽器同源策略限制,當前域名的js只能讀取同域下的視窗屬性。 
一個網站的網址組成包括協議名,子域名,主域名,埠號。比如https://www.github.com/80

其中https是協議名,www.github.com是子域名,github.com是主域名,埠號是80,當在在頁面中從一個url請求資料時,如果這個url的協議名、子域名、主域名、埠號任意一個有一個不同,就會產生跨域問題。

PS:下瀏覽器中的 file://域擁有的許可權很高,WebKit可以讀取磁碟上的檔案,IE可以執行CMD,這裡大家可以盡情發揮想象,能做的事情太多了!

跨域解決方法小結

  1. 最簡單也最常見:使用jsonp ,即json with padding(內填充),顧名思義,就是把JSON填充到一個盒子裡
  2. 一勞永逸:直接在伺服器端設定跨域資源訪問 CORS(Cross-Origin Resource Sharing),設定Request Header頭中Access-Control-Allow-Origin為指定可獲取資料的域名
  3. 簡單有效:直接請求一張圖片
  4. 找”爸爸”:通過修改document.domain來跨子域
  5. 哥倆好:通過window.name來跨域接收資料
  6. 新石器時代:使用HTML5的window.postMessage方法跨域

jsonp

核心思想:瀏覽器的script、img、iframe標籤是不受同源策略限制的 ,所以通過script標籤引入一個js檔案,這個js檔案載入成功後會執行我們在url引數中指定的callback函式,並把把我們需要的json資料作為引數傳入。在伺服器端,當req.params引數中帶有callback屬性時,則把資料作為callback的引數執行,並拼接成一個字串後返回。 
- 優點:相容性好,在很古老的瀏覽器中也可以用,簡單易用,支援瀏覽器與伺服器雙向通訊。 
- 缺點:只支援GET請求,且只支援跨域HTTP請求這種情況(不支援HTTPS

網頁端的程式碼如下 
jsonp 
建立一個函式tryJSONPadding,並在script標籤的源地址中加入這個函式名,伺服器端(Node.js寫的後端)的處理如下 
伺服器端的處理

CORS

核心思想:在伺服器端通過檢查請求頭部的origin,從而決定請求應該成功還是失敗。具體的方法是在服務端設定Response Header響應頭中的Access-Control-Allow-Origin為對應的域名,實現了CORS(跨域資源共享),這裡出於在安全性方面的考慮就是儘量不要用 *,但對於一些不重要的資料則隨意,例如圖片。下圖是某公司阿里雲伺服器上的CORS設定 
CROS

Node.js實現CORS的方法也很簡單,如圖。 
NodeJS

圖片ping

因為在瀏覽器中,JS指令碼和圖片是可以跨域的,所以我們可以直接新建一個圖片物件,然後在地址中存放一些簡單,這種方法只支援get秦秋,且只能單向地向伺服器傳送請求,在統計廣告曝光次數中比較常見。 
圖片ping

尋找相同主域document.domain

對於以下的這兩個域名,可以看到他們的主域名都是 example.com,相同於有一個共同的爸爸,且此方法只適用於兩個iframe之間的跨域

http://www.example.com/a.html 和http://bbs.example.com/b.html)
  • 1
  • 2

下面是另外一篇文章中的例子。 
框架一
框架二

window.name

window物件中其實包含了黑魔法的,window.name屬性就是其中之一,不同域的框架把想要共享的資訊放在window.name裡面且此方法只適用於兩個iframe之間的跨域

a.com/getDomainData.htmla.com/getDomainData.htmlb.com/data.htmlb.com/data.htmla.com/null.htmla.com/null.html獲得資料將iframe的src改為a.com/null.html,跳回原來的域執行回撥函式,並銷燬iframe,關閉null.html

HTML5 中的window.postMessage方法

window.postMessage(message,targetOrigin) 方法是html5新引進的特性,可以使用它來向其它的window物件傳送訊息,無論這個window物件是屬於同源或不同源,目前IE8+、FireFox、Chrome、Opera等瀏覽器都已經支援window.postMessage方法。這種方法不能和服務端交換資料,只能在兩個視窗(iframe)之間交換資料 
www.example.com中主動發起連線 
發起連線
處於安全考慮,另一個域下的指令碼中需要驗證訊息orgin來源後為http://www.example.com後再發送訊息 
驗證後傳送訊息 
event物件,這裡的origin為http://localhost:81,僅作為演示 
origin示意圖