什麼是跨域
首先我們需要了解什麼是同源策略 (Same origin policy),目前所有 browser 都遵守此策略。
同源策略目的是資訊安全,防止他人竊取數據或 CSRF(Cross-site request forgery)。
所謂同源是指三個相同:
- 協議相同 (Protocol: http)
- 域名相同 (Domain: example.com)
- 端口相同 (Host: 80)
非同源情況下,browser 對它有何限制:
Cookie,LocalStorage和IndexDB無法讀取DOM無法獲得Ajax請求被阻止
只要三個【以上】不相同的話,就是跨域!
跨域是指當前 browser 一個網站可以向另一個網站請求讀寫資源。也就是說發起請求 abc.com (origin) 與請求指向資源 xxx.com (origin) 不相同就是跨域。但由於 browser 考量安全機制 (同源策略) 對跨域請求會做出限制!
實現跨域
前面說了 browser 對跨域作出限制,如何實現跨域?
- JSONP
- CORS (Cross-origin resource sharing)
- 待續
JSONP
JSONP -> Json + Padding
JSONP 是利用 script 標籤來實現跨域和達到請求資源的目的。
本质上 client 和 server 會約定好函數名稱
請求方:前端 (browser/client)
響應方:後端 (server)
// 但不是說 script 是跨域,
// 只是 script 不受域名限制
// script -> 只能 get
<script src="可以請求任意網站東西"></script>
JSONP 基本概念
您:server
我:client
大概有 8 個步驟
- 我要訪問馬雲網站 (例:jackma.com),
- 我要請求您的數據,請把數據給我,
- 然後您把數據給
callMeFunc的參數裡 - 我前端先前已經準備好
callMeFunc - 您給我返回一個
JavaScript程式為callMeFunc({...}), - 我前端就會處理後續工作!
JSONP 實現:
- 首先請求方會創建一個
script元素,然後 src 指向另一個資源地址 (後端),同時(告訴後端)傳一個query參數?callback=callMeFunc如 (http://abc.com?name=allen&callback=callMeFunc)。 - server 會根據
query callback來調用callMeFunc也給對應數據作為參數,response 數據給請求方 (client/browser) - 當
callMeFunc被調用後,會執行callMeFunc函數 - 請求方就可以獲取到對應數據
圖1
圖2
我們來實作 JSONP 【以下】
// 請求方 client/browser
// 1. 我會創建一個動態 script 標籤,
// 2. src 請求獲取 (get) 數據。
// 3. 由於 server 要面對的東西太多,我沒辦法告訴它具體詳細,
// 4. 所以我就給予它 query 參數,
// 5. 讓 server 自己去獲取 query 的 key。
// 6. server 知道 client 想要調用哪個函數後,
// 7. server 把 client 想要數據都給該函數裡參數。
// 8. 然後把該調用函數 response 給 client
// 9. client 收到 response 訊息後 (圖2),
// 10. 顯然會執行該函數。
window.callMeFunc = function (data) {
console.log(data)
let amountData = data.data
amount.innerText = amountData
}
button.addEventListener('click', (e) => {
let script = document.createElement('script')
script.src = 'http://jackma.com:8002/pay?callback=callMeFunc'
document.body.appendChild(script)
script.onload = function (e) {
e.currentTarget.remove()
}
script.onerror = function (e) {
alert('fails')
e.currentTarget.remove()
}
})
// 響應方 server
else if (path === '/pay') {
// jackma.com 後台
// 1. client 請求資源路徑匹配條件滿足,會執行以下動作。
// 2. 主要特別說明: response 給 client 端訊息過程,
// 3. server 會根據 query 的 key 去調用對應 key (callMeFunc) 函數,
// 4. 以及把 client 想要數據作為參數 (數據) 傳遞給 callMeFunc 函數。
// 5. 最後 server 會做出響應訊息告訴 client,
// 6. 我 (server) 將把你 (client) 想要調用函數(渴望數據)給你,你快去接收它吧 (圖2)!
var amount = fs.readFileSync('./db', 'utf8') // 讀取 100
var newAmount = amount - 1
fs.writeFileSync('./db', newAmount)
response.setHeader('Content-Type', 'application/javascript')
response.write(`
${query.callback}({
success: true,
data: ${newAmount}
})
`)
response.end()
}
CORS (Cross-origin resource sharing)
中文是跨源資源共享
當使用ajax時在不同源情況下,無法通訊。唯有麻煩後台在response header設定Access-Control-Allow-origin,告訴 browser,我們是朋友需要共享資源。解決了 ajax 只能同源限制。使用 cors 主要是 server 是否開啟跨域,否則我們前端無法獲取響應資源。
只要在後端
response header設定Access-Control-Allow-origin, 指定允許 A網站。
如果是多個不同域可以這樣設定Access-Control-Allow-origin, *。
關於更多 Ajax 跨域,請到 link
面試題
請問 JSONP 為什麼不接受 POST 請求
- 因為
JSONP是動態創建script來實現,我們動態創建script只能用get請求。