前端跨域致命連環問
theme: fancy
本文正在參加「金石計劃」
在面試的時候,面試官問了我一個問題:“你知道如何實現跨域嗎?”
我點了點頭,心中不屑,隨後答道:
跨域是由於瀏覽器的同源策略所導致的,瀏覽器的同源策略是指只有“協議、域名、埠”相同我們才能進行通訊,當有一個不滿足的時候,我們就無法進行跨域。
現在常見的一些手段比如:“JSONP、CORS、WEBPACK配置”
JSONP
然後第二問題來了:“那你知道 JSONP 是如何實現的嗎?”
我皺眉思索了一陣:“這是一種民間的解決方案,應該是利用了 script 標籤不受瀏覽器的同源策略影響的性質來做的,當然還需要前後端的配合。”
“那你知道前後端具體是怎麼配合的嗎?”
我愣了一下,還要這麼細麼????
後來回去查了一下,我們可以這麼做
- 客戶端事先準備一個接收資料的全域性函式
- 客戶端解析道外聯的Script標籤,發出請求
- 服務端收到請求,返回函式的呼叫
- 客戶端收到資料,執行回撥。
程式碼嘛,可以看下面的:
1. 在發請求前,準備一個全域性的接收函式
ts
window.myCallback = (res) => {
console.log(res)
}
2. 在 html 建立 script 標籤,發出請求
ts
<html>
....
<script>
window.myCallback = (res)=>{ //這裡為上一步定義的全域性函式
console.log(res)
}
</script>
<script url="xxx?callback=myCallback">
//script標籤的請求必須在寫在定義全域性函式之後
//這裡需將全域性函式的函式名作為引數callback的value傳遞
//這裡callback這個鍵名是前後端約定好的
</script>
</body>
</html>
3. 服務端接收到請求,將如下資料返回
ts
myCallback({
name: 'ahreal',
age: 18,
})
4. 客戶端接收到服務端的相應,相當於:
ts
<html>
....
<script>
window.myCallback = (res)=>{ //這裡為上一步定義的全域性函式
console.log(res)
}
</script>
<script> //將接收到的資料作為script標籤裡面的內容展開執行
myCallback({
name:'ahreal',
age:18
})
</script>
</body>
</html>
CORS
面試官看我 JSONP 矇住了,就轉頭來問我 CORS。
那你知道 CORS 一般咋使用嗎?
知道啊,我們可以配置 Access-Control-Allow-Origin
來選擇我們允許跨域的域名,如果前端請求之後返回值帶有 Access-Control-Allow-xxx
那多半是可以進行跨域請求;對於複雜請求呢,我們需要傳送一個預檢請求,需要攜帶 Access-Control-Request-Method & Access-Control-Request-Headers
,如果返回值有 Access-Control-Allow-xxx
那就應該是可以。
嗯嗯,那你知道如何給 CORS 設定 Cookie 嗎?
What???
這又是個啥,之前沒見過啊。
明說不會,這一 Part 才結束。
下來查了一下是怎麼回事:
在
CORS
請求中,如果想要傳遞Cookie
,就要滿足以下三個條件: 1. 在請求中設定withCredentials
為true
該屬性是一個
Boolean
型別,當非同步物件設定了WithCredentials=true
時,瀏覽器會保留下響應的Cookie
等資訊,並且下次傳送請求時將其攜帶。ts var xhr = new HMLHttpRequest(); xhr.withCredentials = true; axios.default.withCredentials = true;
2. 在響應頭設定:Access-Control-Allow-Credentials
設定為true
Access-Control-Allow-Credentials
該頭是可選的,是一個bool
值,它若為true
就有兩個作用:
- 在跨域請求的響應中允許
Set-Cookie
響應頭瀏覽器收到響應後,瀏覽器根據此頭判斷是否讓自己的
withCredentials
屬性生效在響應頭中設定:
Access-Control-Allow-Origin
設定為非*
服務端的
Access-Control-Allow-Origin
設定為非 *
服務端的
Access-Control-Allow-Origin
這個響應頭的值不能說萬用字元*
,而只能是具體的值,否則會出現報錯。
那麼這就是本篇文章的全部內容了
點個贊再走吧~