前端開發的跨域問題詳解
同源與跨域問題
同源策略: 為了阻止cookie在不同的網站之間傳輸
同源: 協議相同, 域名相同, 埠號相同
兩個頁面的上面三點都相同, 才是同一個網站, 就是同源
http協議的埠號預設是80, 可省
http: // www.baidu.com [:80] /dir/index.html
協議 域名 80埠,可省
跨域問題的產生:
我們寫的前端程式碼是放在一臺網頁伺服器中的, 公司中介面資料是放在另一臺資料伺服器中的,
我們在我們這臺伺服器中訪問介面資料就會產生跨域
(PS 為什麼會產生跨域:
因為兩臺伺服器在網際網路中的域名一定是不一樣的 -->每臺計算機在網路中都有一個唯一的ip標識.
域名不一樣的, 所以一定會跨域)
比方說我們前端程式碼部署在前端伺服器中, 前端html頁面的地址是
我們在這個index.html中傳送ajax請求, 請求地址是另一臺伺服器中的地址
那麼因為域名不同, 所以這兩個頁面不是屬於同一個網站, 造成跨域
所以ajax獲取不到資料
我們現在每次開發時, 程式碼都是放到本地伺服器中的, 所以是同一個伺服器, 所以一直沒有跨域情況產生
jsonp解決跨域問題 --> jsonp的演變
原理:
伺服器端返回一個函式fn(實參), 這個函式一定是帶引數的,前端呼叫這個函式fn(形參), 這樣後臺就把資料傳過來了
原理的原理:
script可以請求跨域的檔案內容, 並將檔案內容當成js程式碼執行
比方說我們在後臺的http://www.baidu.com/json.php檔案中寫上
<?php echo “alert(666)”?>
然後在本地伺服器中的http://localhost.index.html中引入
這樣開啟index.html檔案, 就可以跨域請求到(訪問到)不是同源網站的json.php檔案, 並將檔案中的程式碼當成js程式碼執行, 就這樣我們就得到伺服器中的資料了
(這裡雖然是php檔案, 但是我們訪問這個php頁面時, 因為伺服器會先執行自己的php檔案中的程式碼, 將結果返回給瀏覽器, 所以我們訪問這個php檔案時, 得到的是alert(666)這個js程式碼)
那麼我們在json.php中echo ”var a = ‘data’”
然後在index.html中console.log(a) 就會打印出data, 實現後臺資料跨域拿到前臺(隱藏點是script引入的js程式碼就是當前頁面中寫的js程式碼了)
優化方法是:
在index.html中定義一個全域性方法
function fn(data) { console.log(data)}
然後我們後臺的json.php中echo “fn(我們想要返回的資料)”
這樣我們在前臺呼叫這個函式的時候, 就能打印出我們想要後端的資料了
這個函式起名字是前端起的, 但是“假”呼叫時在後端, 真呼叫還是在前端
但是這裡還有一個缺點: 後臺得根據前端的這個函式名提前寫死
優化是:
在我們的script中傳入引數
前端中的這個全域性函式名還是得先定下來, 比方叫fn
php.son檔案中 $callback = $_GET[callback] echo “$callback(‘要傳輸的資料’)”
上面的是jsonp的優化過程, 實際用起來不方便, jquery將jsonp封裝到了ajax方法中
$.ajax({
datatype: ‘jsonp’ 之前預設不寫是json型別, 現在需要跨域, 所以告訴ajax一聲
})
cors解決跨域問題
cross origin resource sharing 跨域資源共享
要求: 瀏覽器ie10+, 伺服器允許跨域
如果公司使用流行框架開發專案的話, 那麼就不用考慮相容問題了, 因為至少ie9+才可以使用流行框架
跨域行為造成瀏覽器中不能拿到資料的原理:
這是瀏覽器自己造成的, 無論你跨不跨域, 只要你訪問伺服器, 伺服器都會給在響應中給你返回資料, 但是瀏覽器會自己判斷自己有沒有做相應的設定, 如果沒有, 就會自動忽略不同源的網站的響應, 報跨域的錯誤.
jsonp對比cors
jsonp沒有相容問題, 但是隻支援get請求, 所以資料大小有限制
cors必須瀏覽器ie10+, 支援所有請求, 資料大小沒有限制
但是兩者都需要伺服器進行允許跨域的設定, 光憑前端沒法跨域, 所以我們前端很快樂啊, 啥都不用做, 就是告訴後臺,得跨域!
跨域問題的終極解決方式 -->反向代理
反向代理也能解決跨域問題, 並且是the most fuking awesome的解決跨域方式, 沒有相容問題, 大小限制
在伺服器中進行相應配置, 前端不需要訪問api.json這個不同源的頁面, 正常訪問網頁伺服器中的某個頁面, 網頁伺服器就會自動將你這個請求, 通過它自己的設定代理訪問資料伺服器中的介面, 拿回資料, 然後再通過網頁伺服器返回給你, 就好像你是在網頁伺服器中拿資料一樣
同樣, 前端啥也不用做,啊哈哈哈...