硬核知識(shí)點(diǎn)——瀏覽器中的三類(lèi)五種請(qǐng)求
對(duì)瀏覽器的請(qǐng)求進(jìn)行劃分,可以分為三類(lèi):一般請(qǐng)求、Ajax請(qǐng)求、WebSocket請(qǐng)求,對(duì)于每種請(qǐng)求都有不同的產(chǎn)生方式,今天就以這個(gè)思想為主線來(lái)一起嘮一嘮。
一、一般請(qǐng)求
此處說(shuō)的一般請(qǐng)求就是指瀏覽器會(huì)直接顯示響應(yīng)體數(shù)據(jù),這些請(qǐng)求會(huì)刷新\跳轉(zhuǎn)頁(yè)面。換個(gè)更加容易理解的說(shuō)法吧,指的就是控制臺(tái)Network面板中除了XHR和WS部分顯示的請(qǐng)求。例如js、css、img資源。
二、Ajax請(qǐng)求
Ajax請(qǐng)求也是由瀏覽器發(fā)出,但是不會(huì)對(duì)界面進(jìn)行任何操作,只是調(diào)用監(jiān)視的回調(diào)函數(shù)并傳入響應(yīng)相關(guān)數(shù)據(jù),發(fā)出Ajax請(qǐng)求可以通過(guò)三種方式:XHR、Fetch、Axios,其余的均不是Ajax請(qǐng)求。
2.1 XHR
最早將Ajax推到歷史舞臺(tái)的關(guān)鍵技術(shù)就是XMLHttpRequest(XHR)對(duì)象,雖然目前已經(jīng)有了一些過(guò)時(shí)的嫌疑,但是還是很有必要提一下它。下面就按照一個(gè)請(qǐng)求的整個(gè)生命周期來(lái)看一看該技術(shù)。
一、 對(duì)象的實(shí)例化
既然要使用XHR,第一步就是要將該對(duì)象實(shí)例化
- const xhr = new XMLHttpRequest();
二、初始化操作
將對(duì)象實(shí)例化后是不是緊接著就需要進(jìn)行初始化操作,到底該請(qǐng)求要發(fā)給誰(shuí)、通過(guò)什么請(qǐng)求發(fā)、該請(qǐng)求到底是同步發(fā)還是異步發(fā)
- xhr.open(method, url, async)
三、請(qǐng)求頭設(shè)置
了解網(wǎng)絡(luò)的同學(xué)本肯定知道請(qǐng)求頭的概念,既然要與后端打交道,請(qǐng)求頭還是有必要進(jìn)行設(shè)置的(默認(rèn)的配置不一定滿足我們高大上的需求),例如想發(fā)送json格式的內(nèi)容,這個(gè)時(shí)候就需要設(shè)置Content-Type為application/json
- xhr.setRequestHeader('Content-Type', 'application/json');
四、接收請(qǐng)求的準(zhǔn)備工作
瀏覽器除了設(shè)置常見(jiàn)的請(qǐng)求頭外,還需要指定響應(yīng)數(shù)據(jù)類(lèi)型,得到響應(yīng)后后自動(dòng)解析。目前支持的類(lèi)型有string、arraybuffer、blob、document、json、text、ms-stream。
- xhr.responseType('json')
五、發(fā)送請(qǐng)求
前期工作都準(zhǔn)備好了,接下來(lái)就是激動(dòng)人心的時(shí)刻了,看好呀,要按開(kāi)始鍵發(fā)送請(qǐng)求啦。
- xhr.send(data)
六、監(jiān)聽(tīng)響應(yīng)
我喊一聲美女,人家肯定要回應(yīng)一下呀,畢竟顏值在這,不回應(yīng)該是多么不給面子的一件事呀!!!為了等待人家的回應(yīng),則需要分三步進(jìn)行:
- 進(jìn)入監(jiān)聽(tīng)狀態(tài),放在這就是通過(guò)onreadystatechange進(jìn)行監(jiān)聽(tīng)。
- 等待正面回應(yīng)。readyStatus表征目前的狀態(tài),當(dāng)readyStatus為4(請(qǐng)求完成),響應(yīng)算是接收到了
- 處理響應(yīng)。不能一股腦的處理全部響應(yīng)吧,畢竟也是要面子的人,我肯定只希望接收我喜歡的信息吧,就喜歡狀態(tài)碼在200~299之間的,別的一概pass掉。
- xhr.onreadystatechange = () => {
- if (xhr.readyState == 4) {
- if (xhr.status >= 200 && xhr.status < 300) {
- console.log(xhr.response);
- }
- }
- }
七、中斷請(qǐng)求
正常流程算是走完了,肯定還有非正常流程,發(fā)起請(qǐng)求后我后悔了,不想得到對(duì)方的回應(yīng)了,此時(shí)仍然有辦法——中斷請(qǐng)求
- xhr.abort()
注:本文不是文檔學(xué)習(xí),詳細(xì)使用請(qǐng)見(jiàn)https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest
2.2 Fetch
長(zhǎng)江后浪推前浪,互聯(lián)網(wǎng)技術(shù)發(fā)展這么快,出現(xiàn)了新的技術(shù)(Fetch)能夠執(zhí)行XMLHttpRequest對(duì)象的所有任務(wù),該技術(shù)使用更容易,接口更現(xiàn)代化,能夠在Web工作線程等現(xiàn)代Web工具中使用。(Fetch必須是異步,XMLHttpRequest可同步可異步)。
- const payload = JSON.stringify({
- test: 'test'
- });
- let headersObj = new Headers({
- 'Content-Type':'application/json'
- });
- let request = new Request('http://localhost:8080');
- fetch(request, {
- method: 'POST',
- body: payload,
- headers: headersObj
- })
- .then((response) => response.json())
- .then(console.log)
上述代碼雖然簡(jiǎn)單,但是已經(jīng)囊括了Fetch API中所有的概念:fetch、Headers、Request、Response、Body混入。
1.fetch()
fetch()方法暴露在全局作用域中,包括主頁(yè)面執(zhí)行線程、模塊和工作線程,調(diào)用該方法,瀏覽器就會(huì)向給定URL發(fā)送請(qǐng)求。
(1)fetch(input[, init]):接收兩個(gè)參數(shù),input為要獲取的資源,__init為一個(gè)配置對(duì)象,配置需要傳入的參數(shù),滿足更多復(fù)雜的需求
(2)返回一個(gè)promise對(duì)象,從而鏈?zhǔn)降倪M(jìn)行處理
2.Headers
相當(dāng)于 response/request 的頭信息,可以使你查詢到這些頭信息,或者針對(duì)不同的結(jié)果做不同的操作。該對(duì)象包含檢索、設(shè)置、添加、刪除,設(shè)置完自己需要的頭信息后就可以將其掛載到fetch中的配置信息中。
3.Request
該對(duì)象是獲取資源請(qǐng)求的接口,暴露了請(qǐng)求和相關(guān)信息??梢詫⒃搶?duì)象的實(shí)例作為fetch函數(shù)中的第一個(gè)參數(shù)
4.Response
該對(duì)象是獲取資源響應(yīng)的接口,并暴露了響應(yīng)的相關(guān)信息。
5.Body混入
提供了與 response/request 中的 body 有關(guān)的方法,可以定義它的內(nèi)容形式以及處理方式。在Body混入中提供了5個(gè)方法,用于將ReadableStream轉(zhuǎn)存到緩沖區(qū)的內(nèi)存中,將緩沖區(qū)轉(zhuǎn)換為某種JavaScript對(duì)象類(lèi)型,以及通過(guò)Promise產(chǎn)生結(jié)果。
(1)Body.text():返回Promise,解決將緩沖區(qū)轉(zhuǎn)存得到的UTF-8格式字符串
(2)Body.json():返回Promise,解決將緩沖區(qū)轉(zhuǎn)存得到的JSON
(3)Body.formData():返回Promise,解決將緩沖區(qū)轉(zhuǎn)存得到的FormData實(shí)例
(4)Body.arrayBuffer():返回Promise,解決將緩沖區(qū)轉(zhuǎn)存得到的ArrayBuffer
(5)Body.text():返回Promise,解決將緩沖區(qū)轉(zhuǎn)存得到的Blob實(shí)例
2.3 Axios
Axios應(yīng)該是目前前端最流行的Ajax請(qǐng)求庫(kù),具有以下特點(diǎn):
- 基于Promise的異步Ajax請(qǐng)求庫(kù)
- 瀏覽器端/node端都可以使用
- 支持請(qǐng)求/響應(yīng)攔截器
- 支持請(qǐng)求取消
- 請(qǐng)求/響應(yīng)數(shù)據(jù)轉(zhuǎn)換
- 批量發(fā)送請(qǐng)求
- // 默認(rèn)配置
- axios.defaults.baseURL = 'http://localhost:8080'
- // 請(qǐng)求攔截器
- axios.interceptors.request.use(
- config => {
- console.log('request interceptor resolved');
- return config;
- },
- error => {
- console.log('request interceptor rejected');
- return Promise.reject(error);
- }
- );
- // 響應(yīng)攔截器
- axios.interceptors.response.use(
- response => {
- console.log('response interceptor resolved');
- return response;
- },
- error => {
- console.log('response interceptor rejected');
- return Promise.reject(error);
- }
- );
- let cancel; // 用于保存取消請(qǐng)求的函數(shù)
- axios('/', {
- method: 'post',
- headers: {
- 'Content-Type': 'application/json'
- },
- data: {
- test: 'test'
- },
- // 取消請(qǐng)求
- cancelToken: new axios.CancelToken((c) => {
- cancel = c;
- })
- })
- .then((response) => {
- console.log(response.data)
- })
- // 若想取消請(qǐng)求,直接調(diào)用下面函數(shù)
- // cancel();
上述代碼已經(jīng)囊括了Axios庫(kù)中大多數(shù)核心內(nèi)容,包括axios()函數(shù)、默認(rèn)設(shè)置、請(qǐng)求/響應(yīng)攔截器、取消請(qǐng)求(內(nèi)部設(shè)計(jì)的很巧妙,想知道的請(qǐng)看下期講解)
1.axios()
完成相應(yīng)配置并發(fā)送請(qǐng)求,調(diào)用方式有多種語(yǔ)法糖,同學(xué)們可以按需使用。
2.默認(rèn)設(shè)置
通過(guò)axios.defaults.xxx可以完成很多全局配置,提高代碼的復(fù)用。(提高復(fù)用真是完美的編碼思想)
3.請(qǐng)求/響應(yīng)攔截器
請(qǐng)求攔截器的作用就是在請(qǐng)求發(fā)送之前先進(jìn)行一些列的處理;響應(yīng)攔截器的作用就是觸發(fā)請(qǐng)求的回調(diào)之前執(zhí)行響應(yīng)攔截器,對(duì)響應(yīng)做一些預(yù)處理操作
4.取消請(qǐng)求
通過(guò)配置cancelToken對(duì)象并緩存用于取消請(qǐng)求的cancel函數(shù),在需要的時(shí)候觸發(fā)該函數(shù)取消請(qǐng)求(內(nèi)部其實(shí)就是調(diào)用的xhr.abort())
對(duì)于更多使用見(jiàn)詳細(xì)使用文檔https://github.com/axios/axios
三、WebSocket請(qǐng)求
下面來(lái)聊聊這個(gè)傳奇協(xié)議——WebSocket,WebSockt通過(guò)一個(gè)長(zhǎng)時(shí)連接實(shí)現(xiàn)與服務(wù)器全雙工、雙向的通信。(特別提醒:同源策略不適用于WebSocket)
- let ws = new WebSocket('ws://127.0.0.1:8080');
- // 在連接建立成功時(shí)
- ws.onopen = () => {
- ws.send('websocket')
- }
- // 在接收到消息時(shí)
- ws.onmessage = (event) => {
- console.log(event.data);
- }
- // 在發(fā)生錯(cuò)誤時(shí)
- ws.onerror = () => {
- console.log('error');
- }
- // 在連接關(guān)閉時(shí)
- ws.onclose = () => {
- console.log('close');
- }
上述代碼已經(jīng)囊括大部分WebSocket的概念,實(shí)例化WebSocket建立與服務(wù)端的連接;通過(guò)事件監(jiān)聽(tīng)即可了解WebSokcet連接目前的狀態(tài);通過(guò)send()函數(shù)即可向服務(wù)端發(fā)送內(nèi)容;當(dāng)服務(wù)端發(fā)送消息時(shí)即可觸發(fā)message事件,通過(guò)event.data屬性獲取其有效載荷。
本篇文章雖然比較簡(jiǎn)單,但是可以幫助我們認(rèn)清楚請(qǐng)求其實(shí)是分為三類(lèi)的,這是我最最最大的收獲,歡迎小伙伴們能夠給出自己的想法。
本文轉(zhuǎn)載自微信公眾號(hào)「執(zhí)鳶者」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系執(zhí)鳶者公眾號(hào)。