一、前端進行網路請求的關注點
大多數情況下,在前端發起一個網路請求我們只需關注下面幾點:
- 傳入基本引數(
url
,請求方式) - 請求引數、請求引數型別
- 設定請求頭
- 獲取響應的方式
- 獲取響應頭、響應狀態、響應結果
- 異常處理
- 攜帶
cookie
設定 - 跨域請求
二、前端進行網路請求的方式
form
表單、ifream
、重新整理頁面Ajax
- 非同步網路請求的開山鼻祖jQuery
- 一個時代fetch
-Ajax
的替代者axios、request
等眾多開源庫
三、關於網路請求的疑問
Ajax
的出現解決了什麼問題- 原生
Ajax
如何使用 jQuery
的網路請求方式fetch
的用法以及坑點- 如何正確的使用
fetch
- 如何選擇合適的跨域方式
帶著以上這些問題、關注點我們對幾種網路請求進行一次全面的分析。
四、Ajax的出現解決了什麼問題
在Ajax
出現之前,web
程式是這樣工作的:
這種互動的的缺陷是顯而易見的,任何和伺服器的互動都需要重新整理頁面,使用者體驗非常差,Ajax
的出現解決了這個問題。Ajax
全稱Asynchronous JavaScript + XML
(非同步JavaScript
和XML
)
使用Ajax
,網頁應用能夠快速地將增量更新呈現在使用者介面上,而不需要過載(重新整理)整個頁面。
Ajax
本身不是一種新技術,而是用來描述一種使用現有技術集合實現的一個技術方案,瀏覽器的XMLHttpRequest
是實現Ajax
最重要的物件(IE6
以下使用ActiveXObject
)。
儘管X
在Ajax
中代表XML
, 但由於JSON
的許多優勢,比如更加輕量以及作為Javascript
的一部分,目前JSON
的使用比XML
更加普遍。
五、原生Ajax的用法
這裡主要分析XMLHttpRequest
物件,下面是它的一段基礎使用:
var xhr = new XMLHttpRequest();
xhr.open('post','www.xxx.com',true)
// 接收返回值
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 ){
if(xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
console.log(xhr.responseText);
}
}
}
// 處理請求引數
postData = {"name1":"value1","name2":"value2"};
postData = (function(value){
var dataString = "";
for(var key in value){
dataString += key+"="+value[key]+"&";
};
return dataString;
}(postData));
// 設定請求頭
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
// 異常處理
xhr.onerror = function() {
console.log('Network request failed')
}
// 跨域攜帶cookie
xhr.withCredentials = true;
// 發出請求
xhr.send(postData);
複製程式碼
下面分別對XMLHttpRequest
物件常用的的函式、屬性、事件進行分析。
函式
open
用於初始化一個請求,用法:
xhr.open(method, url, async);
複製程式碼
method
:請求方式,如get、post
url
:請求的url
async
:是否為非同步請求
send
用於傳送HTTP
請求,即呼叫該方法後HTTP
請求才會被真正發出,用法:
xhr.send(param)
複製程式碼
param
:http請求的引數,可以為string、Blob
等型別。
abort
用於終止一個ajax
請求,呼叫此方法後readyState
將被設定為0
,用法:
xhr.abort()
複製程式碼
setRequestHeader
用於設定HTTP
請求頭,此方法必須在open()
方法和send()
之間呼叫,用法:
xhr.setRequestHeader(header, value);
複製程式碼
getResponseHeader
用於獲取http
返回頭,如果在返回頭中有多個一樣的名稱,那麼返回的值就會是用逗號和空格將值分隔的字串,用法:
var header = xhr.getResponseHeader(name);
複製程式碼
屬性
readyState
用來標識當前XMLHttpRequest
物件所處的狀態,XMLHttpRequest
物件總是位於下列狀態中的一個:
值 | 狀態 | 描述 |
---|---|---|
0 | UNSENT |
代理被建立,但尚未呼叫 open() 方法。 |
1 | OPENED |
open() 方法已經被呼叫。 |
2 | HEADERS_RECEIVED |
send() 方法已經被呼叫,並且頭部和狀態已經可獲得。 |
3 | LOADING |
下載中; responseText 屬性已經包含部分資料。 |
4 | DONE |
下載操作已完成。 |
status
表示http
請求的狀態, 初始值為0
。如果伺服器沒有顯式地指定狀態碼, 那麼status
將被設定為預設值, 即200
。
responseType
表示響應的資料型別,並允許我們手動設定,如果為空,預設為text
型別,可以有下面的取值:
值 | 描述 |
---|---|
"" |
將 responseType 設為空字串與設定為"text" 相同, 是預設型別 (實際上是 DOMString )。 |
"arraybuffer" |
response 是一個包含二進位制資料的JavaScript ArrayBuffer 。 |
"blob" |
response 是一個包含二進位制資料的 Blob 物件 。 |
"document" |
response 是一個HTML Document 或XML XMLDocument ,這取決於接收到的資料的 MIME 型別。 |
"json" |
response 是一個 JavaScript 物件。這個物件是通過將接收到的資料型別視為JSON 解析得到的。 |
"text" |
response 是包含在DOMString 物件中的文字。 |
response
返回響應的正文,返回的型別由上面的responseType
決定。
withCredentials
ajax
請求預設會攜帶同源請求的cookie
,而跨域請求則不會攜帶cookie
,設定xhr
的withCredentials
的屬性為true
將允許攜帶跨域cookie
。
事件回撥
onreadystatechange
xhr.onreadystatechange = callback;
複製程式碼
當readyState
屬性發生變化時,callback會被觸發。
onloadstart
xhr.onloadstart = callback;
複製程式碼
在ajax
請求傳送之前(readyState==1
後, readyState==2
前),callback
會被觸發。
onprogress
xhr.onprogress = function(event){
console.log(event.loaded / event.total);
}
複製程式碼
回撥函式可以獲取資源總大小total
,已經載入的資源大小loaded
,用這兩個值可以計算載入進度。
onload
xhr.onload = callback;
複製程式碼
當一個資源及其依賴資源已完成載入時,將觸發callback
,通常我們會在onload
事件中處理返回值。
異常處理
onerror
xhr.onerror = callback;
複製程式碼
當ajax
資源載入失敗時會觸發callback
。
ontimeout
xhr.ontimeout = callback;
複製程式碼
當進度由於預定時間到期而終止時,會觸發callback
,超時時間可使用timeout
屬性進行設定。
六、jQuery對Ajax的封裝
在很長一段時間裡,人們使用jQuery
提供的ajax
封裝進行網路請求,包括$.ajax、$.get、$.post
等,這幾個方法放到現在,我依然覺得很實用。
$.ajax({
dataType: 'json', // 設定返回值型別
contentType: 'application/json', // 設定引數型別
headers: {'Content-Type','application/json'},// 設定請求頭
xhrFields: { withCredentials: true }, // 跨域攜帶cookie
data: JSON.stringify({a: [{b:1, a:1}]}), // 傳遞引數
error:function(xhr,status){ // 錯誤處理
console.log(xhr,status);
},
success: function (data,status) { // 獲取結果
console.log(data,status);
}
})
複製程式碼
$.ajax
只接收一個引數,這個引數接收一系列配置,其自己封裝了一個jqXHR
物件,有興趣可以閱讀一下jQuary-ajax 原始碼
常用配置:
url
當前頁地址。傳送請求的地址。
type
型別:String
請求方式 ("POST"
或"GET"
), 預設為 "GET"
。注意:其它HTTP
請求方法,如PUT
和 DELETE
也可以使用,但僅部分瀏覽器支援。
timeout
型別:Number
設定請求超時時間(毫秒)。此設定將覆蓋全域性設定。
success
型別:Function
請求成功後的回撥函式。
jsonp
在一個jsonp
請求中重寫回撥函式的名字。這個值用來替代在"callback=?"
這種GET
或POST
請求中URL
引數裡的"callback"
部分。
error 型別:Function
。請求失敗時呼叫此函式。
注意:原始碼裡對錯誤的判定:
isSuccess = status >= 200 && status < 300 || status === 304;
複製程式碼
返回值除了這幾個狀態碼都會進error
回撥。
dataType
"xml": 返回 XML 文件,可用 jQuery 處理。
"html": 返回純文字 HTML 資訊;包含的 script 標籤會在插入 dom 時執行。
"script": 返回純文字 JavaScript 程式碼。不會自動快取結果。除非設定了 "cache" 引數。注意:在遠端請求時(不在同一個域下),所有 POST 請求都將轉為 GET 請求。(因為將使用 DOM 的 script標籤來載入)
"json": 返回 JSON 資料 。
"jsonp": JSONP 格式。使用 JSONP 形式呼叫函式時,如 "myurl?callback=?" jQuery 將自動替換 ? 為正確的函式名,以執行回撥函式。
"text": 返回純文字字串
複製程式碼
data
型別:String
使用JSON.stringify
轉碼
complete
型別:Function
請求完成後回撥函式 (請求成功或失敗之後均呼叫)。
async
型別:Boolean
預設值:true
。預設設定下,所有請求均為非同步請求。如果需要傳送同步請求,請將此選項設定為 false
。
contentType
型別:String
預設值: "application/x-www-form-urlencoded"
。傳送資訊至伺服器時內容編碼型別。
鍵值對這樣組織在一般的情況下是沒有什麼問題的,這裡說的一般是,不帶巢狀型別JSON
,也就是 簡單的JSON
,形如這樣:
{
a: 1,
b: 2,
c: 3
}
複製程式碼
但是在一些複雜的情況下就有問題了。 例如在 Ajax
中你要傳一個複雜的 json
對像,也就說是物件嵌陣列,陣列中包括物件,你這樣傳:application/x-www-form-urlencoded
這種形式是沒有辦法將複雜的JSON
組織成鍵值對形式。
{
data: {
a: [{
x: 2
}]
}
}
複製程式碼
可以用如下方式傳遞複雜的json
物件
$.ajax({
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify({a: [{b:1, a:1}]})
})
複製程式碼
七、jQuery的替代者
近年來前端MV*
的發展壯大,人們越來越少的使用jQuery
,我們不可能單獨為了使用jQuery
的Ajax api
來單獨引入他,無可避免的,我們需要尋找新的技術方案。
尤雨溪在他的文件中推薦大家用axios
進行網路請求。axios
基於Promise
對原生的XHR
進行了非常全面的封裝,使用方式也非常的優雅。另外,axios
同樣提供了在node
環境下的支援,可謂是網路請求的首選方案。
未來必定還會出現更優秀的封裝,他們有非常周全的考慮以及詳細的文件,這裡我們不多做考究,我們把關注的重點放在更底層的APIfetch
。
Fetch API
是一個用用於訪問和操縱HTTP管道的強大的原生 API。
這種功能以前是使用 XMLHttpRequest實現的。Fetch提供了一個更好的替代方法,可以很容易地被其他技術使用,例如 Service Workers。Fetch還提供了單個邏輯位置來定義其他HTTP相關概念,例如CORS和HTTP的擴充套件。
可見fetch
是作為XMLHttpRequest
的替代品出現的。
使用fetch
,你不需要再額外載入一個外部資源。但它還沒有被瀏覽器完全支援,所以你仍然需要一個polyfill
。
八、fetch的使用
一個基本的 fetch請求:
const options = {
method: "POST", // 請求引數
headers: { "Content-Type": "application/json"}, // 設定請求頭
body: JSON.stringify({name:'123'}), // 請求引數
credentials: "same-origin", // cookie設定
mode: "cors", // 跨域
}
fetch('http://www.xxx.com',options)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson); // 響應資料
})
.catch(function(err){
console.log(err); // 異常處理
})
複製程式碼
Fetch API
提供了一個全域性的fetch()
方法,以及幾個輔助物件來發起一個網路請求。
fetch()
fetch()
方法用於發起獲取資源的請求。它返回一個promise
,這個 promise
會在請求響應後被 resolve
,並傳回 Response
物件。
Headers
可以通過Headers()
建構函式來建立一個你自己的headers
物件,相當於 response/request
的頭資訊,可以使你查詢到這些頭資訊,或者針對不同的結果做不同的操作。
var myHeaders = new Headers();
myHeaders.append("Content-Type", "text/plain");
複製程式碼
Request
通過Request()
建構函式可以建立一個Request
物件,這個物件可以作為fetch
函式的第二個引數。
Response
在fetch()
處理完promises
之後返回一個Response
例項,也可以手動建立一個Response
例項。
九、fetch polyfill原始碼分析
由於fetch
是一個非常底層的API
,所以我們無法進一步的探究它的底層,但是我們可以藉助它的polyfill
探究它的基本原理,並找出其中的坑點。
程式碼結構
由程式碼可見,polyfill
主要對Fetch
API提供的四大物件進行了封裝:
fetch 封裝
程式碼非常清晰:
- 構造一個
Promise
物件並返回 - 建立一個
Request
物件 - 建立一個
XMLHttpRequest
物件 - 取出
Request
物件中的請求url
,請求方發,open
一個xhr
請求,並將Request
物件中儲存的headers
取出賦給xhr xhr onload
後取出response
的status
、headers
、body
封裝Response
物件,呼叫resolve
。
異常處理
可以發現,呼叫reject
有三種可能:
-
1.請求超時
-
2.請求失敗
注意:當和伺服器建立簡介,並收到伺服器的異常狀態碼如404、500
等並不能觸發onerror
。當網路故障時或請求被阻止時,才會標記為 reject
,如跨域、url
不存在,網路異常等會觸發onerror
。
所以使用fetch當接收到異常狀態碼都是會進入then而不是catch。這些錯誤請求往往要手動處理。
- 3.手動終止
可以在request
引數中傳入signal
物件,並對signal
物件新增abort
事件監聽,當xhr.readyState
變為4
(響應內容解析完成)後將signal物件的abort事件監聽移除掉。
這表示,在一個fetch
請求結束之前可以呼叫signal.abort
將其終止。在瀏覽器中可以使用AbortController()
建構函式建立一個控制器,然後使用AbortController.signal
屬性
這是一個實驗中的功能,此功能某些瀏覽器尚在開發中
Headers封裝
在header物件中維護了一個map
物件,建構函式中可以傳入Header
物件、陣列、普通物件型別的header
,並將所有的值維護到map
中。
之前在fetch
函式中看到呼叫了header
的forEach
方法,下面是它的實現:
可見header
的遍歷即其內部map
的遍歷。
另外Header
還提供了append、delete、get、set
等方法,都是對其內部的map
物件進行操作。
Request物件
Request
物件接收的兩個引數即fetch
函式接收的兩個引數,第一個引數可以直接傳遞url
,也可以傳遞一個構造好的request
物件。第二個引數即控制不同配置的option
物件。
可以傳入credentials、headers、method、mode、signal、referrer
等屬性。
這裡注意:
- 傳入的
headers
被當作Headers
建構函式的引數來構造header物件。
cookie處理
fetch函式中還有如下的程式碼:
if (request.credentials === 'include') {
xhr.withCredentials = true
} else if (request.credentials === 'omit') {
xhr.withCredentials = false
}
複製程式碼
預設的credentials
型別為same-origin
,即可攜帶同源請求的coodkie。
然後我發現這裡polyfill的實現和MDN-使用Fetch以及很多資料是不一致的:
mdn: 預設情況下,fetch 不會從服務端傳送或接收任何 cookies
於是我分別實驗了下使用polyfill
和使用原生fetch
攜帶cookie的情況,發現在不設定credentials
的情況下居然都是預設攜帶同源cookie
的,這和文件的說明說不一致的,查閱了許多資料後都是說fetch
預設不會攜帶cookie,下面是使用原生fetch
在瀏覽器進行請求的情況:
然後我發現在MDN-Fetch-Request已經指出新版瀏覽器credentials
預設值已更改為same-origin
,舊版依然是omit
。
確實MDN-使用Fetch這裡的文件更新的有些不及時,誤人子弟了...
Response物件
Response
物件是fetch
呼叫成功後的返回值:
回顧下f
etch中對
Response`的操作:
xhr.onload = function () {
var options = {
status: xhr.status,
statusText: xhr.statusText,
headers: parseHeaders(xhr.getAllResponseHeaders() || '')
}
options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')
var body = 'response' in xhr ? xhr.response : xhr.responseText
resolve(new Response(body, options))
}
複製程式碼
Response
建構函式:
可見在建構函式中主要對options
中的status、statusText、headers、url
等分別做了處理並掛載到Response
物件上。
建構函式裡面並沒有對responseText
的明確處理,最後交給了_initBody
函式處理,而Response
並沒有主動宣告_initBody
屬性,程式碼最後使用Response
呼叫了Body
函式,實際上_initBody
函式是通過Body
函式掛載到Response
身上的,先來看看_initBody
函式:
可見,_initBody
函式根據xhr.response
的型別(Blob、FormData、String...
),為不同的引數進行賦值,這些引數在Body
方法中得到不同的應用,下面具體看看Body
函式還做了哪些其他的操作:
Body
函式中還為Response
物件掛載了四個函式,text、json、blob、formData
,這些函式中的操作就是將_initBody中得到的不同型別的返回值返回。
這也說明了,在fetch
執行完畢後,不能直接在response
中獲取到返回值而必須呼叫text()、json()
等函式才能獲取到返回值。
這裡還有一點需要說明:幾個函式中都有類似下面的邏輯:
var rejected = consumed(this)
if (rejected) {
return rejected
}
複製程式碼
consumed函式:
function consumed(body) {
if (body.bodyUsed) {
return Promise.reject(new TypeError('Already read'))
}
body.bodyUsed = true
}
複製程式碼
每次呼叫text()、json()
等函式後會將bodyUsed
變數變為true
,用來標識返回值已經讀取過了,下一次再讀取直接丟擲TypeError('Already read')
。這也遵循了原生fetch
的原則:
因為Responses物件被設定為了 stream 的方式,所以它們只能被讀取一次
十、fetch的坑點
VUE
的文件中對fetch
有下面的描述:
使用
fetch
還有很多別的注意事項,這也是為什麼大家現階段還是更喜歡axios
多一些。當然這個事情在未來可能會發生改變。
由於fetch
是一個非常底層的API
,它並沒有被進行很多封裝,還有許多問題需要處理:
- 不能直接傳遞
JavaScript
物件作為引數 - 需要自己判斷返回值型別,並執行響應獲取返回值的方法
- 獲取返回值方法只能呼叫一次,不能多次呼叫
- 無法正常的捕獲異常
- 老版瀏覽器不會預設攜帶
cookie
- 不支援
jsonp
十一、對fetch的封裝
請求引數處理
支援傳入不同的引數型別:
function stringify(url, data) {
var dataString = url.indexOf('?') == -1 ? '?' : '&';
for (var key in data) {
dataString += key + '=' + data[key] + '&';
};
return dataString;
}
if (request.formData) {
request.body = request.data;
} else if (/^get$/i.test(request.method)) {
request.url = `${request.url}${stringify(request.url, request.data)}`;
} else if (request.form) {
request.headers.set('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8');
request.body = stringify(request.data);
} else {
request.headers.set('Content-Type', 'application/json;charset=UTF-8');
request.body = JSON.stringify(request.data);
}
複製程式碼
cookie攜帶
fetch
在新版瀏覽器已經開始預設攜帶同源cookie
,但在老版瀏覽器中不會預設攜帶,我們需要對他進行統一設定:
request.credentials = 'same-origin'; // 同源攜帶
request.credentials = 'include'; // 可跨域攜帶
複製程式碼
異常處理
當接收到一個代表錯誤的 HTTP 狀態碼時,從 fetch()返回的 Promise 不會被標記為 reject, 即使該 HTTP 響應的狀態碼是 404 或 500。相反,它會將 Promise 狀態標記為 resolve (但是會將 resolve 的返回值的 ok 屬性設定為 false ),僅當網路故障時或請求被阻止時,才會標記為 reject。
因此我們要對fetch
的異常進行統一處理
.then(response => {
if (response.ok) {
return Promise.resolve(response);
}else{
const error = new Error(`請求失敗! 狀態碼: ${response.status}, 失敗資訊: ${response.statusText}`);
error.response = response;
return Promise.reject(error);
}
});
複製程式碼
返回值處理
對不同的返回值型別呼叫不同的函式接收,這裡必須提前判斷好型別,不能多次呼叫獲取返回值的方法:
.then(response => {
let contentType = response.headers.get('content-type');
if (contentType.includes('application/json')) {
return response.json();
} else {
return response.text();
}
});
複製程式碼
jsonp
fetch
本身沒有提供對jsonp
的支援,jsonp
本身也不屬於一種非常好的解決跨域的方式,推薦使用cors
或者nginx
解決跨域,具體請看下面的章節。
fetch封裝好了,可以愉快的使用了。
嗯,axios真好用...
十二、跨域總結
談到網路請求,就不得不提跨域。
瀏覽器的同源策略限制了從同一個源載入的文件或指令碼如何與來自另一個源的資源進行互動。這是一個用於隔離潛在惡意檔案的重要安全機制。通常不允許不同源間的讀操作。
跨域條件:協議,域名,埠,有一個不同就算跨域。
下面是解決跨域的幾種方式:
nginx
使用nginx
反向代理實現跨域,參考我這篇文章:前端開發者必備的nginx知識
cors
CORS
是一個W3C
標準,全稱是"跨域資源共享"(Cross-origin resource sharing)
。它允許瀏覽器向跨源伺服器,發出XMLHttpRequest
請求。
服務端設定Access-Control-Allow-Origin
就可以開啟CORS
。 該屬性表示哪些域名可以訪問資源,如果設定萬用字元則表示所有網站都可以訪問資源。
app.all('*', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
next();
});
複製程式碼
jsonp
script
標籤的src
屬性中的連結可以訪問跨域的js
指令碼,利用這個特性,服務端不再返回JSON
格式的資料,而是返回一段呼叫某個函式的js
程式碼,在src
中進行了呼叫,這樣實現了跨域。
jquery
對jsonp
的支援:
$.ajax({
type : "get",
url : "http://xxxx"
dataType: "jsonp",
jsonp:"callback",
jsonpCallback: "doo",
success : function(data) {
console.log(data);
}
});
複製程式碼
fetch、axios
等並沒有直接提供對jsonp
的支援,如果需要使用這種方式,我們可以嘗試進行手動封裝:
(function (window,document) {
"use strict";
var jsonp = function (url,data,callback) {
// 1.將傳入的data資料轉化為url字串形式
// {id:1,name:'jack'} => id=1&name=jack
var dataString = url.indexof('?') == -1? '?': '&';
for(var key in data){
dataString += key + '=' + data[key] + '&';
};
// 2 處理url中的回撥函式
// cbFuncName回撥函式的名字 :my_json_cb_名字的字首 + 隨機數(把小數點去掉)
var cbFuncName = 'my_json_cb_' + Math.random().toString().replace('.','');
dataString += 'callback=' + cbFuncName;
// 3.建立一個script標籤並插入到頁面中
var scriptEle = document.createElement('script');
scriptEle.src = url + dataString;
// 4.掛載回撥函式
window[cbFuncName] = function (data) {
callback(data);
// 處理完回撥函式的資料之後,刪除jsonp的script標籤
document.body.removeChild(scriptEle);
}
document.body.appendChild(scriptEle);
}
window.$jsonp = jsonp;
})(window,document)
複製程式碼
postMessage跨域
postMessage()
方法允許來自不同源的指令碼採用非同步方式進行有限的通訊,可以實現跨文字檔、多視窗、跨域訊息傳遞。
//捕獲iframe
var domain = 'http://scriptandstyle.com';
var iframe = document.getElementById('myIFrame').contentWindow;
//傳送訊息
setInterval(function(){
var message = 'Hello! The time is: ' + (new Date().getTime());
console.log('blog.local: sending message: ' + message);
//send the message and target URI
iframe.postMessage(message,domain);
},6000);
複製程式碼
//響應事件
window.addEventListener('message',function(event) {
if(event.origin !== 'http://davidwalsh.name') return;
console.log('message received: ' + event.data,event);
event.source.postMessage('holla back youngin!',event.origin);
},false);
複製程式碼
postMessage
跨域適用於以下場景:同瀏覽器多視窗間跨域通訊、iframe
間跨域通訊。
WebSocket
WebSocket
是一種雙向通訊協議,在建立連線之後,WebSocket
的 server
與 client
都能主動向對方傳送或接收資料而不受同源策略的限制。
function WebSocketTest(){
if ("WebSocket" in window){
alert("您的瀏覽器支援 WebSocket!");
// 開啟一個 web socket
var ws = new WebSocket("ws://localhost:3000/abcd");
ws.onopen = function(){
// Web Socket 已連線上,使用 send() 方法傳送資料
ws.send("傳送資料");
alert("資料傳送中...");
};
ws.onmessage = function (evt) {
var received_msg = evt.data;
alert("資料已接收...");
};
ws.onclose = function(){
// 關閉 websocket
alert("連線已關閉...");
};
} else{
// 瀏覽器不支援 WebSocket
alert("您的瀏覽器不支援 WebSocket!");
}
}
複製程式碼
文章首發
想閱讀更多優質文章,或者需要文章中思維導圖原始檔可關注我的github部落格,歡迎star✨。
文中如有錯誤,歡迎在評論區指正,謝謝閱讀。