面試必考題吧,所以在這會詳細介紹以下內容
- 跨域產生的原因
- 羅列最常用的解決方法
- 分析各種方法原理
- 羅列各種方法優缺點
什麼是跨域
由於瀏覽器廠商對安全性的考慮,提出了瀏覽器的同源策略
做為解決方案。它是一個用於隔離潛在惡意檔案的重要安全機制。同源即協議
、域名
、埠
三者一致。不同源即跨域。
如果沒有同源策略會怎麼樣?
比如:當你訪問了 餅夕夕的網站
// HTML
// 餅夕夕.com 內嵌 拼多多.com
<iframe name="pinduoduo" src="www.pinduoduo.com"></iframe>
// JS
// 由於沒有同源策略的限制,釣魚網站可以直接拿到別的網站的Dom
// 所以 餅夕夕.com 可以在 拼多多.com 輸入賬號密碼處埋點
const $iframe = window.frames['pinduoduo'];
const $pwd = $iframe.document.getElementById('password');
console.log(`你的密碼已洩露: ${$pwd}`)
複製程式碼
解決方案(主流)
1. JSONP -> get請求跨域 原理:script和img等標籤沒有跨域限制 實現方案:(舉例)
// HTML 插入標籤
<script src="127.0.0.1/x/account?cb=say" ></script>
// JS
function say(name, age) {
console.log(`${name}, ${age} 歲`)
}
// 伺服器返回response
say('zmz', 18)
// 那麼客戶端在script onload時會執行say方法
// 結束
複製程式碼
2. iframe+form實現post請求跨域 原理:利用form表單target屬性,將post請求提交給隱藏的iframe,使頁面不跳轉
var data = {
name: 'zmz',
age: 18
}
var url = 'http://localhost/say';
var $iframe = document.createElement('iframe');
$iframe.name = 'iframePost';
$iframe.style.display = 'none';
document.body.appendChild($iframe);
$iframe.addEventListener('load', function(e) {
console.log($iframe.contentWindow)
})
const form = document.createElement('form');
const ipt = document.createElement('input');
form.action = url;
form.enctype = 'application/json;'
form.method = 'post';
// 最核心的一行程式碼
// 在指定的iframe中執行form
form.target = $iframe.name;
for (var name in data) {
ipt.name = name;
ipt.value = data[name];
form.appendChild(ipt.cloneNode());
}
form.style.display = 'none';
document.body.appendChild(form);
form.submit();
document.body.removeChild(form)
複製程式碼
3. CORS 跨源資源共享
原理:新版XMLHttpRequest(ajax2.0)特性,伺服器白名單
伺服器端設定response.setHeader("Access-Control-Allow-xxx...
附:ajax2.0新特性
- 可以設定HTTP請求的時限
xhr.timeout
- 可以使用
FormData
物件管理表單資料 - 可以上傳檔案 >> 同上
- 可以請求不同域名下的資料(跨域請求)
- 可以獲取伺服器端的二進位制資料
xhr.responseType = 'blob'
- 可以獲得資料傳輸的進度資訊
xhr.upload.process
CORS分類
- 簡單請求(自行搜尋)
- 在請求頭資訊中指定
Origin
- 在請求頭資訊中指定
- 非簡單請求
- 會傳送預檢請求(options),返回狀態碼204
5. 代理 原理:伺服器之間沒有跨域限制 具體實現:
// Nginx配置
server{
# 監聽9099埠
listen 9099;
# 域名是localhost
server_name localhost;
# 匹配到都轉發到http://localhost:9871
location ^~ /api {
proxy_pass http://localhost:9871;
}
}
複製程式碼
5. postMessage 原理:postMessage可以處理各種瀏覽器視窗之間的通訊問題。 具體實現:
// 傳送方
window.frames['crossDomainIframe']
iframe.postMessage('我想要資料', 'http://localhost:8088')
window.addEventListener('message', function () {
if (e.origin === 'http://localhost:2333') {
console.log('收到', e.data)
}
}
// 接收方
window.addEventListener('message', (e) => {
if (e.origin === 'http://localhost:8088') {
console.log(e.data)
e.source.postMessage('給,你要的資料', e.origin);
}
})
複製程式碼
6. WebSocket 原理:新協議(socket) 實現方案:類似postMessage 附:
- socket.io框架能解決相容性問題
各種方式對比
- JSONP和iframe+from相容性很好
- 但是錯誤處理和RESTful介面統一是個問題
- CORS最簡單粗暴
- 9102年了。微軟都不維護Win7了。
- 代理
- 肯定會慢一丟丟咯,而且要找運維配
- postMessage
- 處理視窗間通訊,- -。不嫌麻煩可以用來跨域
- WebSocket
- 處理長連線,附帶跨域
End
文章分享同步於: github.com/zhongmeizhi…