手寫ajax
GET請求
let xmlhttp侮攀;
if (window.XMLHttpRequest)
{
// IE7+, Firefox, Chrome, Opera, Safari 瀏覽器執(zhí)行代碼
xmlhttp=new XMLHttpRequest();
}
else
{
// IE6, IE5 瀏覽器執(zhí)行代碼
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
console.log(xmlhttp.response); // 設(shè)置responseType為json時,用response獲取數(shù)據(jù),無需JSON.parse
}
if (xmlhttp.readyState === 4 && xmlhttp.status !== 200) {
throw new Error(`請求出錯,錯誤碼:${xmlhttp.status}摩泪,錯誤說明: ${xmlhttp.statusText}`);
}
}
xmlhttp.open("GET", url, true);
// 服務(wù)器返回的數(shù)據(jù)為json數(shù)據(jù),不需要parse轉(zhuǎn)換
// 不設(shè)置的話客戶端默認(rèn)收到的是字符串劫谅,客戶端需要parse轉(zhuǎn)換成json數(shù)據(jù)
xmlhttp.responseType = "json";
xmlhttp.send();
POST請求
let xmlhttp见坑;
if (window.XMLHttpRequest)
{
// IE7+, Firefox, Chrome, Opera, Safari 瀏覽器執(zhí)行代碼
xmlhttp=new XMLHttpRequest();
}
else
{
// IE6, IE5 瀏覽器執(zhí)行代碼
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
console.log(xmlhttp.response);
}
if (xmlhttp.readyState === 4 && xmlhttp.status !== 200) {
throw new Error(`請求出錯,錯誤碼:${xmlhttp.status}捏检,錯誤說明: ${xmlhttp.statusText}`);
}
}
xmlhttp.open("POST", url, true);
// 發(fā)送給服務(wù)器的為json數(shù)據(jù)荞驴,即請求頭的content-type類型為json類型
// 不設(shè)置的話服務(wù)器默認(rèn)收到的是字符串,服務(wù)器需要parse轉(zhuǎn)換成json數(shù)據(jù)類型
xmlhttp.setRequestHeader("Content-Type", "application/json");
// 服務(wù)器返回的數(shù)據(jù)為json數(shù)據(jù)贯城,不需要parse轉(zhuǎn)換
// 不設(shè)置的話客戶端默認(rèn)收到的是字符串熊楼,客戶端需要parse轉(zhuǎn)換成json數(shù)據(jù)
xmlhttp.responseType = "json";
xmlhttp.send(JSON.stringify({method: "ajax",sendType: "post"}));
發(fā)送json數(shù)據(jù)
方法一
設(shè)置xmlhttp.responseType
,發(fā)送時用JSON.stringify
將對象轉(zhuǎn)化為字符串能犯,添加請求頭content-type
類型為application/json
鲫骗,接收數(shù)據(jù)用xmlhttp.response
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
console.log(xmlhttp.response);
}
}
xmlhttp.open("POST", url, true);
// 發(fā)送給服務(wù)器的為json數(shù)據(jù),即請求頭的content-type類型為json類型
// 不設(shè)置的話服務(wù)器默認(rèn)收到的是字符串踩晶,服務(wù)器需要parse轉(zhuǎn)換成json數(shù)據(jù)類型
xmlhttp.setRequestHeader("Content-Type", "application/json");
// 服務(wù)器返回的數(shù)據(jù)為json數(shù)據(jù)执泰,不需要parse轉(zhuǎn)換
// 不設(shè)置的話客戶端默認(rèn)收到的是字符串,客戶端需要parse轉(zhuǎn)換成json數(shù)據(jù)
xmlhttp.responseType = "json";
xmlhttp.send(JSON.stringify({method: "ajax",sendType: "post"}));
方法二
發(fā)送時JSON.stringify格式化發(fā)送數(shù)據(jù)為json渡蜻,服務(wù)器接收數(shù)據(jù)后需要調(diào)用JSON.parse將字符串轉(zhuǎn)化為對象术吝,服務(wù)器發(fā)送數(shù)據(jù)給客戶端時,需要調(diào)用JSON.stringify茸苇∨挪裕客戶端接收數(shù)據(jù)時需要調(diào)用JSON.parse
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
console.log(JSON.parse(xmlhttp.responseText));
}
}
xmlhttp.open("POST", url, true);
xmlhttp.send(JSON.stringify({method: "ajax",sendType: "post"}));
設(shè)置超時
// 默認(rèn)為0,即為不超時
xmlhttp.timeout = 4000;
跨域攜帶cookie
xhr.withCredentials = true;
終止請求
xmlhttp.abort();
設(shè)置請求頭
xmlhttp.setRequestHeader("Content-Type", "application/json");
設(shè)置響應(yīng)類型
// ""(默認(rèn)值等同于text)学密、arraybuffer淘衙、blob、document则果、json幔翰、text
// 其中如果設(shè)置json及document,但是服務(wù)器返回的據(jù)不是指定類型的化西壮,response的值為null
xmlhttp.responseType = "json";
強制設(shè)置響應(yīng)類型
xmlhttp.overrideMimeType('text/xml');
獲取響應(yīng)頭
xmlhttp.getResponseHeader("Content-Type")
axios的用法
GET請求
axios.get(url).then(function (response) {
console.log(response);
}).catch(function (error) {
console.log(error);
});
POST請求
axios.post(url, {
"firstName": 'Fred',
"lastName": 'Flintstone'
}).then(function (response) {
console.log(response);
}).catch(function (error) {
console.log(error);
});
添加請求頭
// `headers` are custom headers to be sent
headers: {'X-Requested-With': 'XMLHttpRequest'},
設(shè)置超時時間
// 請求超時時間(毫秒)
timeout: 1000,
跨域攜帶cookie
// 是否攜帶cookie信息
withCredentials: false, // default
設(shè)置響應(yīng)類型
// 響應(yīng)格式
// 可選項 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
responseType: 'json', // 默認(rèn)值是json
終止請求
var CancelToken = axios.CancelToken;var source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// handle error
}});
// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');
var CancelToken = axios.CancelToken;var cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// An executor function receives a cancel function as a parameter
cancel = c;
})});
// cancel the request
cancel();
相關(guān)鏈接:
axios中文文檔
fetch的用法
Fetch底層并不是XMLHttp技術(shù)(ajax)遗增,F(xiàn)etch 的核心在于對 HTTP 接口的抽象,包括 Request款青,Response做修,Headers,Body,以及用于初始化異步請求的 global fetch饰及。得益于 JavaScript 實現(xiàn)的這些抽象好的 HTTP 模塊蔗坯,其他接口能夠很方便的使用這些功能。除此之外燎含,F(xiàn)etch 還利用到了請求的異步特性——它是基于 Promise 的宾濒。
GET請求
fetch(url)
.then(function (response) {
// debugger;
// let data = response.text(); // json 數(shù)據(jù)轉(zhuǎn)字符串,不報錯
// let data = response.formData(); // json 報錯 類型錯誤
// let data = response.json(); // json 不報錯屏箍,json
// let data = response.arrayBuffer(); // json 不報錯绘梦, arraybuffer
// let data = response.blob(); // json 不報錯, blob
// let data = response.text(); // string 不報錯 string
// let data = response.formData(); // string 報錯 類型錯誤
// let data = response.json(); // string 報錯 類型錯誤
// let data = response.arrayBuffer(); // string 不報錯赴魁, arraybuffer
// let data = response.blob(); // string 不報錯卸奉, blob
return data;
})
.then(function (myJson) {
// debugger;
console.log(myJson);
});
注意:
- 第一個then方法為已經(jīng)發(fā)送成功并收到服務(wù)器返回的數(shù)據(jù),準(zhǔn)備處理response響應(yīng)體數(shù)據(jù)颖御,第二個then方法為處理完成response響應(yīng)體數(shù)據(jù)榄棵。
- 響應(yīng)體數(shù)據(jù)處理時,如果服務(wù)器返回數(shù)據(jù)與準(zhǔn)備獲取的類型(
let data = response.text()
這里的text即為客戶端準(zhǔn)備獲取的類型)不一致時潘拱,json和formData這兩個會在不一致時報錯疹鳄,其余的不會報錯。與ajax保持類似芦岂。
POST 請求
let data = {
method: "POST",
sendData: "adsf"
}
fetch(url, {
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json' // 不設(shè)置服務(wù)器不識別為json
},
method: "POST"
}).then(response => {
// let data = response.text(); // json 數(shù)據(jù)轉(zhuǎn)字符串尚辑,不報錯
// let data = response.formData(); // json 報錯 類型錯誤
let data = response.json(); // json 不報錯,json
// let data = response.arrayBuffer(); // json 不報錯盔腔, arraybuffer
// let data = response.blob(); // json 不報錯, blob
// let data = response.text(); // string 不報錯 string
// let data = response.formData(); // string 報錯 類型錯誤
// let data = response.json(); // string 報錯 類型錯誤
// let data = response.arrayBuffer(); // string 不報錯月褥, arraybuffer
// let data = response.blob(); // string 不報錯弛随, blob
return data;
}).then(response => {
console.log(response);
})
注意:
- 如果不設(shè)置正確的header中的content-type類型的化,服務(wù)獲取到的數(shù)據(jù)類型并不會是指定類型宁赤,這一點與ajax保持一致
添加請求頭
fetch(url, {
headers: {
'user-agent': 'Mozilla/4.0 MDN Example',
'content-type': 'application/json'
}
})
.then(response => response.json()) // parses response to JSON
獲取響應(yīng)頭
fetch(url, {
headers: {
'user-agent': 'Mozilla/4.0 MDN Example',
'content-type': 'application/json'
}
})
.then(response => {
console.log(response.headers);// 可通過這里的content-type類型決定返回哪種數(shù)據(jù)類型
if(response.headers.get("content-type") === "application/json") {
return response.json()
}
return response.text()
})
跨域攜帶cookie
// 注意fetch在不跨域的情況下是攜帶cookie的舀透,接收set-cookie頭。 在跨域的情況下是不攜帶cookie决左,不接受set-cookie
// 這一點和ajax一致
fetch(url, {credentials: 'include' })
超時設(shè)置
方案一 設(shè)置setTimeout
function request(url, wait) {
return new Promise((resolve, reject) => {
let status = 0; // 0 等待 1 完成 2 超時
// 設(shè)置定時器愕够,超時reject,這個只有一個promise
let timer = setTimeout(() => {
if (status === 0) {
status = 2;
timer = null;
console.log("超時");
reject(new Error("request timeout error"));
}
}, wait);
fetch(url)
.then(res => res.json())
.then(res => {
// 清除定時器
if (status !== 2) {
clearTimeout(timer);
timer = null;
status = 1;
resolve(res);
}
});
});
}
// 調(diào)用
request(url).then(json => {
console.log(json);
}).catch(err => {
console.log(err);
// 處理超時
})
方案二 使用Promise.race
// 創(chuàng)建一個setTimeout的promise和一個fetch的promise佛猛,兩個promise進行賽跑(race)惑芭,如果setTimeout先完成,則結(jié)束promise.race继找。
function request(fetchPromise, timeout) {
return Promise.race([
fetchPromise,
new Promise((resolve, reject) => {
setTimeout(() => {
console.log("超時了");
reject(new Error('request timeout')) // 創(chuàng)建Error
}, 3000)
})
]);
}
// 調(diào)用
request(fetch(url), 3000).then(response => response.json()).then(json => {
console.log(json);
}).catch(err => {
console.log(err) // 這個就是剛才創(chuàng)建的超時異常遂跟,或其他請求異常
// 這里處理超時
})
取消請求
方案一 通過reject取消Promise,并不會取消請求的發(fā)送
原理為劫持Promise,添加一個abort方法
// 劫持全局Promise
Promise.prototype.abort = () => Promise.reject(new Error("abort promise"));
// 用函數(shù)包裝
function fetchAbort1(fetchPromise) {
fetchPromise.abort = () => Promise.reject(new Error("abort promise"));
return fetchPromise
}
// 示例
var p = fetch(url).then(response => response.json()).then(json => {
console.log(json);
}).catch(error => {
console.log(error);
});
setTimeout(() => {
console.log("4s后取消了")
p.abort()
}, 4000)
另一種實現(xiàn)(加上Promise.race)
function fetchAbort(fetchPromise) {
var abort_fn = null;
//這是一個可以被reject的promise
var abort_promise = new Promise(function (resolve, reject) {
abort_fn = function () {
reject('abort promise');
};
});
//這里使用Promise.race幻锁,以最快 resolve 或 reject 的結(jié)果來傳入后續(xù)綁定的回調(diào)
var abortable_promise = Promise.race([
fetchPromise,
abort_promise
]);
abortable_promise.abort = abort_fn;
return abortable_promise;
}
// 調(diào)用
var p = fetchAbort(fetch('//a.com/b/c'));
p.then(function(res) {
console.log(res)
}, function(err) {
console.log(err);
});
//假設(shè)fetch要3秒凯亮,但是你想在2秒就放棄了:
setTimeout(function() {
p.abort(); // -> will print "abort promise"
}, 2000);
方案二 通過AbortController 取消fetch請求(處于實驗階段,慎用)哄尔,會取消請求的發(fā)送假消,終止fetch請求
let controller = new AbortController();
let signal = controller.signal;
let timeoutPromise = (timeout) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(new Response("timeout", { status: 504, statusText: "timeout " }));
controller.abort();
}, timeout);
});
}
let requestPromise = (url) => {
return fetch(url, {
signal: signal
});
};
Promise.race([timeoutPromise(1000), requestPromise("https://www.baidu.com")])
.then(resp => {
console.log(resp);
})
.catch(error => {
console.log(error);
});
參考鏈接:
Fetch超時設(shè)置和終止請求
AbortController
postMessage
postMessage()方法允許來自不同源的腳本采用異步方式進行有限的通信,可以實現(xiàn)跨文本檔岭接、多窗口富拗、跨域消息傳遞,只適用于有iframe標(biāo)簽的頁面
父頁面
<iframe src="./child1.html" frameborder="1"></iframe>
<iframe src="./child2.html" frameborder="1"></iframe>
<script>
window.onload = function(params) {
var child1 = window.frames[0];
child1.postMessage('message from parentwindow', '*');// 給1發(fā)消息
var child2 = window.frames[1];
child2.postMessage('message from parentwindow', '*');// 給1發(fā)消息
window.addEventListener('message', function (e) {
console.log(e.data) // 接收消息
}, false)
}
</script>
子頁面一
<h1>child1 page</h1>
<script>
window.onload = function() {
window.top.postMessage('message from child1', "*"); // 給父頁面發(fā)消息
window.addEventListener('message', function (e) {
console.log("child1", e.data); // 接收數(shù)據(jù)
}, false)
}
</script>
子頁面二
<h1>child2 page</h1>
<script>
window.onload = function() {
window.top.postMessage('message from child2', "*"); // 給父頁面發(fā)消息
window.addEventListener('message', function (e) {
console.log("child2", e.data); // 接收數(shù)據(jù)
}, false)
}
</script>
參考連接:
window.postMessage
websocket
// 需要自定義頭協(xié)議
// 需要保持心跳連接
// 需要斷開重連
const sleep = time => new Promise(resolve => {
setTimeout(resolve, time);
})
let count = 0; // 鏈接次數(shù)
function soket(url, wsType = "arraybuffer") {
var ws = new WebSocket(url);
ws.binaryType = wsType; // 設(shè)置數(shù)據(jù)接收類型
ws.onopen = () => {
ws.send("Hello world!"); // 建立連接后發(fā)送驗證消息
};
ws.onmessage = evt => {
console.log(evt.data); // 接收消息后的處理
ws.send("abcd");
}
ws.onclose = async() => {
console.log("ws 連接失敗") // 斷開連接后的處理
count++;
if (count < 5) {
await sleep(500);
soket(url, wsType);
}
};
return ws;
}
Server Sent Events
嚴(yán)格地說亿傅,HTTP 協(xié)議無法做到服務(wù)器主動推送信息媒峡。但是,有一種變通方法葵擎,就是服務(wù)器向客戶端聲明谅阿,接下來要發(fā)送的是流信息(streaming)。
也就是說酬滤,發(fā)送的不是一次性的數(shù)據(jù)包签餐,而是一個數(shù)據(jù)流,會連續(xù)不斷地發(fā)送過來盯串。這時氯檐,客戶端不會關(guān)閉連接,會一直等著服務(wù)器發(fā)過來的新的數(shù)據(jù)流体捏,視頻播放就是這樣的例子冠摄。本質(zhì)上,這種通信就是以流信息的方式几缭,完成一次用時很長的下載河泳。
SSE 就是利用這種機制,使用流信息向瀏覽器推送信息年栓。它基于 HTTP 協(xié)議拆挥,目前除了 IE/Edge,其他瀏覽器都支持某抓。
SSE 與 WebSocket 作用相似纸兔,都是建立瀏覽器與服務(wù)器之間的通信渠道,然后服務(wù)器向瀏覽器推送信息否副。
總體來說汉矿,WebSocket 更強大和靈活。因為它是全雙工通道副编,可以雙向通信负甸;SSE 是單向通道流强,只能服務(wù)器向瀏覽器發(fā)送,因為流信息本質(zhì)上就是下載呻待。如果瀏覽器向服務(wù)器發(fā)送信息打月,就變成了另一次 HTTP 請求。
SSE和websoket的區(qū)別
- SSE 使用 HTTP 協(xié)議蚕捉,現(xiàn)有的服務(wù)器軟件都支持奏篙。WebSocket 是一個獨立協(xié)議。
- SSE 屬于輕量級迫淹,使用簡單秘通;WebSocket 協(xié)議相對復(fù)雜。
- SSE 默認(rèn)支持?jǐn)嗑€重連敛熬,WebSocket 需要自己實現(xiàn)肺稀。
- SSE 一般只用來傳送文本,二進制數(shù)據(jù)需要編碼后傳送应民,WebSocket 默認(rèn)支持傳送二進制數(shù)據(jù)话原。
- SSE 支持自定義發(fā)送的消息類型。
基本用法
// 客戶端
// 判斷是否支持
if("EventSource" in window) {
// 生成EventSource實例
var source = new EventSource(url);
// 建立連接時觸發(fā)
source.onopen = function (event) {
// ...
};
// 接收消息時觸發(fā)
source.onmessage = function (event) {
var data = event.data;
// handle message
};
// 發(fā)生通信錯誤時觸發(fā)
source.onerror = function (event) {
// handle error event
};
}
// 服務(wù)器端
// 發(fā)送以下響應(yīng)頭
Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive
// 發(fā)送響應(yīng)體數(shù)據(jù)示例诲锹,每一條數(shù)據(jù)以\n\n結(jié)尾繁仁,每行按\n分割
: this is a test stream\n\n
data: some text\n\n
data: another message\n
data: with two lines \n\n
服務(wù)器發(fā)送的響應(yīng)體字段
data
// 數(shù)據(jù)內(nèi)容用data字段表示。
data: begin message\n // \n為換行
data: continue message\n\n // \n\n為消息結(jié)尾
data: {\n
data: "foo": "bar",\n
data: "baz", 555\n
data: }\n\n
event
// event字段表示自定義的事件類型归园,默認(rèn)是message事件黄虱。瀏覽器可以用addEventListener()監(jiān)聽該事件。
event: foo\n
data: a foo event\n\n
data: an unnamed event\n\n
event: bar\n
data: a bar event\n\n
id
// id為每一條數(shù)據(jù)的標(biāo)識庸诱,可在連接斷線后捻浦,重新連接時同步信息使用, 因此,這個頭信息可以被視為一種同步機制桥爽∧矗客戶端可以用lastEventId屬性讀取這個值
id: msg1\n
retry
// 服務(wù)器端發(fā)送以下數(shù)據(jù),客戶端會在報錯后等待指定時間重新連接
// 適用于服務(wù)器主動關(guān)閉連接聚谁、網(wǎng)絡(luò)出錯及超時、時間間隔到期等滞诺。
retry: 10000\n
關(guān)閉SSE連接
source.close();
跨域攜帶cookie
var source = new EventSource(url, { withCredentials: true });
自定義事件
// 客戶端 自定義事件foo
source.addEventListener('foo', function (event) {
var data = event.data;
// handle message
}, false);
// 服務(wù)器端 發(fā)送自定義事件foo
event: foo\n
data: a foo event\n\n
關(guān)閉形导、超時及網(wǎng)絡(luò)出錯時的重連
retry: 10000\n
示例
客戶端
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>測試SSE</title>
</head>
<body>
<div id="example"></div>
<script>
var source = new EventSource('http://127.0.0.1:8844/stream');
var div = document.getElementById('example');
source.onopen = function (event) {
div.innerHTML += '<p>Connection open ...</p>';
};
source.onerror = function (event) {
div.innerHTML += '<p>Connection close.</p>';
};
source.addEventListener('connecttime', function (event) {
div.innerHTML += ('<p>Start time: ' + event.data + '</p>');
}, false);
source.onmessage = function (event) {
div.innerHTML += ('<p>Ping: ' + event.data + '</p>');
};
</script>
</body>
</html>
服務(wù)器端
var http = require("http");
var count = 0;
http.createServer(function (req, res) {
var fileName = "." + req.url;
count++;
if (fileName === "./stream") {
res.writeHead(200, {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Access-Control-Allow-Origin": '*',
});
res.write(`: This is a ${count} comment\n`)
res.write("retry: 3000\n");
res.write(`id: ${count}\n`)
res.write("event: connecttime\n");
res.write("data: " + (new Date()) + "\n\n");
// res.end(); // 服務(wù)器關(guān)閉,客戶端在retry時間段后會重新向服務(wù)器發(fā)送連接
// 定時發(fā)送數(shù)據(jù)給客戶端
interval = setInterval(function () {
res.write("data: " + (new Date()) + "\n\n");
}, 1000);
// 關(guān)閉時清除定時器
req.connection.addListener("close", function () {
clearInterval(interval);
}, false);
}
}).listen(8844, "127.0.0.1");
相關(guān)連接:
Server-Sent Events 教程
Server-sent events
ajax习霹、axios朵耕、fetch的區(qū)別
- ajax:底層是ajax,可設(shè)置超時淋叶,可取消請求阎曹,沒有promise封裝,自己處理非200的錯誤
- axios:底層是ajax,可設(shè)置超時处嫌,可取消請求栅贴,通過promise封裝,非200的錯誤進入catch
- fetch:底層是fetch API熏迹,不可設(shè)置超時檐薯,不可取消請求,通過promise封裝注暗,非200的錯誤并不會catch
ajax斷點續(xù)傳
什么是短鏈接坛缕、長連接、短輪詢捆昏、長輪詢
- 短鏈接:請求-響應(yīng)赚楚,響應(yīng)完成后即關(guān)閉連接的為短鏈接
- 長連接:建立完成連接后,不會主動關(guān)閉連接骗卜,長時間保持客戶端與服務(wù)器端的通訊
- 短輪詢:客戶端向服務(wù)器發(fā)送請求宠页,連接建立很短時間后,服務(wù)器關(guān)閉請求膨俐,隨即客戶端再次向服務(wù)器發(fā)送請求勇皇。 與長輪詢相比連接持續(xù)時間短,建立次數(shù)多焚刺。
- 長輪詢:客戶端向服務(wù)器發(fā)送請求敛摘,連接建立很長時間后,服務(wù)器關(guān)閉請求乳愉,隨即客戶端再次向服務(wù)器發(fā)送請求兄淫。與短輪詢相比連接持續(xù)時間長,建立次數(shù)少蔓姚。
什么是跨域捕虽?什么是同源策略,什么是cors
什么是跨域
跨域坡脐,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本泄私。它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScript實施的安全限制备闲。"協(xié)議+域名+端口"不同會產(chǎn)生跨域晌端。
什么是同源策略
同源策略/SOP(Same origin policy)是一種約定,由Netscape公司1995年引入瀏覽器恬砂,它是瀏覽器最核心也最基本的安全功能咧纠,如果缺少了同源策略,瀏覽器很容易受到XSS泻骤、CSFR等攻擊漆羔。所謂同源是指"協(xié)議+域名+端口"三者相同梧奢,即便兩個不同的域名指向同一個ip地址,也非同源演痒。
同源策略限制以下幾種行為:
- Cookie亲轨、LocalStorage 和 IndexDB 無法讀取
- DOM 和 Js對象無法獲得
- AJAX 請求不能發(fā)送
什么是cors
CORS是一個W3C標(biāo)準(zhǔn),全稱是"跨域資源共享"(Cross-origin resource sharing)嫡霞。
它允許瀏覽器向跨源服務(wù)器瓶埋,發(fā)出XMLHttpRequest請求,從而克服了AJAX只能同源使用的限制诊沪。
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Allow-Credentials: true
跨域的幾種方式
- 通過jsonp跨域
- document.domain + iframe跨域
- location.hash + iframe
- window.name + iframe跨域
- postMessage跨域
- 跨域資源共享(CORS)
- nginx代理跨域
- nodejs中間件代理跨域
- WebSocket協(xié)議跨域
參考鏈接
詳解跨域(最全的解決方案)