Axios 是一個基于 promise 的 HTTP 庫,可以用在瀏覽器和 node.js 中。我們知道 Promise 是 js 異步的一種解決方案,它最大的特性就是可以通過 .then 的方式來進(jìn)行鏈?zhǔn)秸{(diào)用。
其實說白了axios是對ajax的封裝,axios有的ajax都有,ajax有的axios不一定有,總結(jié)一句話就是axios是ajax,ajax不止axios。
axios的使用比較簡單,文檔講得也非常清晰,你應(yīng)該先閱讀axios的官方文檔:axios文檔。
在html頁面中直接引入使用:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
以下案例中的get請求地址為crmeb相關(guān)演示站地址,可用于測試獲取!
<script>
const url = 'https://store.crmeb.net/api/pc/get_category_product'
axios({
url: url,
method: 'get', // 這里可以省略,默認(rèn)為get
}).then(res => {
// 返回請求到的數(shù)據(jù)
console.log(res)
}).catch(err => {
// 返回錯誤信息
console.log(err)
})
</script>
<script>
const url = 'https://store.crmeb.net/api/pc/get_category_product'
axios({
url: url,
method: 'get', // 這里可以省略,默認(rèn)為get
// 這里的鍵值對會拼接成這樣url?page=1&limit=3
params: {
page: 1,
limit: 3
}
}).then(res => {
// 返回請求到的數(shù)據(jù)
console.log(res)
}).catch(err => {
// 返回錯誤信息
console.log(err)
})
</script>
<script>
axios({
method: 'post',
url: '/user/12345',
data: {
firstName: 'Fred',
lastName: 'Flintstone'
}
}).then(res => {
// 返回請求到的數(shù)據(jù)
console.log(res)
}).catch(err => {
// 返回錯誤信息
console.log(err)
});
</script>
如果在開發(fā)中需要等到多個接口的數(shù)據(jù)同時請求到后才能繼續(xù)后邊的邏輯,那么即可使用并發(fā)請求,axios并發(fā)請求,使用all方法,all方法的參數(shù)為一個數(shù)組,數(shù)組的每個值可以為一次請求,請求完成后直接.then即可合并兩次請求的數(shù)據(jù),返回結(jié)果為一個數(shù)組!
<script>
axios.all([
axios({
url: 'https://store.crmeb.net/api/pc/get_products',
params: {
page: 1,
limit: 20,
cid: 57,
sid: 0,
priceOrder: '',
news: 0,
}
}),
axios({
url: 'https://store.crmeb.net/api/pc/get_company_info',
})
]).then(results => {
console.log(results)
})
</script>
如果你想自動把這個數(shù)組展開的話在then()方法中傳入axios.spread()方法即可,如下所示:
<script>
axios.all([
axios({
url: 'https://store.crmeb.net/api/pc/get_products',
params: {
page: 1,
limit: 20,
cid: 57,
sid: 0,
priceOrder: '',
news: 0,
}
}),
axios({
url: 'https://store.crmeb.net/api/pc/get_company_info',
})
]).then(axios.spread((res1, res2) => {
console.log(res1);
console.log(res2);
}))
</script>
但在使用vue組件化開發(fā)的時候一般我們會通過npm安裝,引入項目!
npm install axios --save
一般在實際項目中我們并不會像上邊這樣直接去使用axios請求數(shù)據(jù),而是將axios封裝在一個單獨的文件,這樣做的目的主要是用來抽取公共邏輯到一個配置文件里,對這些公共邏輯做一個封裝,即使某一天這個axios框架不維護(hù)了,或者出現(xiàn)了重大bug也不再修復(fù)的時候,我們可以只修改配置文件即可達(dá)到全局修改的目的,如果把每次請求邏輯都寫到對應(yīng)的組件中,那修改起來簡直就是一個噩夢!
在項目的src目錄下創(chuàng)建一個network文件夾,再在其中創(chuàng)建一個request.js文件,路徑為:src/network/request.js
// src/network/request.js
// 引入axios
import axios from 'axios'
// 這里未使用default導(dǎo)出,是為了以后的擴(kuò)展,便于導(dǎo)出多個方法
export function request(config){
// 創(chuàng)建axios實例
const instance = axios.create({
// 這里定義每次請求的公共數(shù)據(jù),例如全局請求頭,api根地址,過期時間等
// 具體參數(shù)可參考axios的官方文檔
baseURL: 'http://demo26.crmeb.net/api',
timeout: 5000
})
// 攔截請求,如果獲取某個請求需要攜帶一些額外數(shù)據(jù)
instance.interceptors.request.use(
config => {
console.log(config);
return config;
}, err => {
console.log(err);
})
// 攔截響應(yīng)
instance.interceptors.response.use(
res => {
console.log(res)
return res.data
}, err => {
console.log(err)
}
)
// 發(fā)送請求
return instance(config)
一般我們會將所有的請求放在一個api.js文件中,將每次請求封裝為一個方法,比如我這里會在request.js的同目錄創(chuàng)建一個api.js文件封裝我們所有的請求。
import { request } from '../api/request'
// 獲取分類
export const getHomeCategory = () => {
return request({
url: '/category'
})
}
// 獲取banner圖
export const getHomeBanner = () => {
return request({
url: '/pc/get_banner'
})
}
之后再在組件中引入調(diào)用導(dǎo)出的相關(guān)接口方法即可,如:
import { getHomeBanner } from "../network/api"
getHomeBanner().then(res => {
console.log(res)
})
以上就是一個簡單的封裝,其中有個攔截請求和攔截響應(yīng),可能很多初學(xué)的人理解起來有點吃力,我在這里以個人淺見闡述,希望能帶給你些許啟發(fā)!
還是發(fā)揮閱讀理解能力,攔截攔截其實就是此路是我開,此樹是我栽,要想過此路,留下買路錢,攔截請求就是比如某些請求需要攜帶一些額外的信息才能訪問,實際項目中最常見的就是需要登錄后才能查看的信息,請求中就必須攜帶token才能訪問,就可以在這里處理,還有攔截響應(yīng),比如請求到數(shù)據(jù)之后,發(fā)現(xiàn)不符合要求,先攔下來處理一下,再返回給前端,這就是一個攔截器的基本工作流程!
如下所示:
// 攔截請求,如果獲取某個請求需要攜帶一些額外數(shù)據(jù)
instance.interceptors.request.use(
config => {
console.log(config);
return config;
}, err => {
console.log(err);
})
// 攔截響應(yīng)
instance.interceptors.response.use(
res => {
console.log(res)
return res.data
}, err => {
console.log(err)
}
)
axios還為我們提供了一些全局配置,如下:
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
當(dāng)然也可以將其配置在我們之前創(chuàng)建的axios實例中,使其只作用于某個實例!
然后來看一下 axios 的所有配置信息:
數(shù)據(jù)來自axios中文文檔
,一般現(xiàn)在流傳的HTTP請求:GET和POST的比較是這樣的:
GET和POST是HTTP的兩個常用方法。
什么是HTTP?
超文本傳輸協(xié)議(HyperText Transfer Protocol -- HTTP)是一個設(shè)計來使客戶端和服務(wù)器順利進(jìn)行通訊的協(xié)議。
HTTP在客戶端和服務(wù)器之間以request-responseprotocol(請求-回復(fù)協(xié)議)工作。
GET- 從指定的服務(wù)器中獲取數(shù)據(jù)
POST- 提交數(shù)據(jù)給指定的服務(wù)器處理
GET方法:
使用GET方法時,查詢字符串(鍵值對)被附加在URL地址后面一起發(fā)送到服務(wù)器:
/test/demo_form.jsp?name1=value1&name2=value2
特點:
· GET請求能夠被緩存
· GET請求會保存在瀏覽器的瀏覽記錄中
· 以GET請求的URL能夠保存為瀏覽器書簽
· GET請求有長度限制
· GET請求主要用以獲取數(shù)據(jù)
POST方法:
使用POST方法時,查詢字符串在POST信息中單獨存在,和HTTP請求一起發(fā)送到服務(wù)器:
POST/test/demo_form.jsp HTTP/1.1
Host:w3schools.com
name1=value1&name2=value2
特點:
· POST請求不能被緩存下來
· POST請求不會保存在瀏覽器瀏覽記錄中
· 以POST請求的URL無法保存為瀏覽器書簽
· POST請求沒有長度限制
GET和POST的區(qū)別:
其他HTTP請求方式
二,本質(zhì)上,這些并不是HTTP的GET和POST兩者請求的區(qū)別,這些區(qū)別是建立在HTML標(biāo)準(zhǔn)對于HTTP協(xié)議的用法的約定之上的。
1. GET和POST與數(shù)據(jù)如何傳遞沒有關(guān)系
GET和POST是由HTTP協(xié)議定義的。在HTTP協(xié)議中,Method和Data(URL, Body, Header)是正交的兩個概念,也就是說,使用哪個Method與應(yīng)用層的數(shù)據(jù)如何傳輸是沒有相互關(guān)系的。
HTTP沒有要求,如果Method是POST數(shù)據(jù)就要放在BODY中。也沒有要求,如果Method是GET,數(shù)據(jù)(參數(shù))就一定要放在URL中而不能放在BODY中。
那么,網(wǎng)上流傳甚廣的這個說法是從何而來的呢?我在HTML標(biāo)準(zhǔn)中,找到了相似的描述。這和網(wǎng)上流傳的說法一致。但是這只是HTML標(biāo)準(zhǔn)對HTTP協(xié)議的用法的約定。怎么能當(dāng)成GET和POST的區(qū)別呢?
而且,現(xiàn)代的Web Server都是支持GET中包含BODY這樣的請求。雖然這種請求不可能從瀏覽器發(fā)出,但是現(xiàn)在的Web Server又不是只給瀏覽器用,已經(jīng)完全地超出了HTML服務(wù)器的范疇了。
2. HTTP協(xié)議對GET和POST都沒有對長度的限制
HTTP協(xié)議明確地指出了,HTTP頭和Body都沒有長度的要求。而對于URL長度上的限制,有兩方面的原因造成:
1. 瀏覽器。據(jù)說早期的瀏覽器會對URL長度做限制。據(jù)說IE對URL長度會限制在2048個字符內(nèi)(流傳很廣,而且無數(shù)同事都表示認(rèn)同)。但我自己試了一下,我構(gòu)造了90K的URL通過IE9訪問live.com,是正常的。網(wǎng)上的東西,哪怕是Wikipedia上的,也不能信。
2. 服務(wù)器。URL長了,對服務(wù)器處理也是一種負(fù)擔(dān)。原本一個會話就沒有多少數(shù)據(jù),現(xiàn)在如果有人惡意地構(gòu)造幾個幾M大小的URL,并不停地訪問你的服務(wù)器。服務(wù)器的最大并發(fā)數(shù)顯然會下降。另一種攻擊方式是,把告訴服務(wù)器Content-Length是一個很大的數(shù),然后只給服務(wù)器發(fā)一點兒數(shù)據(jù),嘿嘿,服務(wù)器你就傻等著去吧。哪怕你有超時設(shè)置,這種故意的次次訪問超時也能讓服務(wù)器吃不了兜著走。有鑒于此,多數(shù)服務(wù)器出于安全啦、穩(wěn)定啦方面的考慮,會給URL長度加限制。但是這個限制是針對所有HTTP請求的,與GET、POST沒有關(guān)系。
前文沒有描述到傳輸和協(xié)議直接的層級對應(yīng)關(guān)系,大概補(bǔ)充下網(wǎng)絡(luò)通信中數(shù)據(jù)傳輸對應(yīng)的協(xié)議,首先了解下OSI(開放式系統(tǒng)互聯(lián):Open System InterConnection)七層 模式,及其對應(yīng)不同層次的協(xié)議。
OSI體系結(jié)構(gòu)TCP/IP相關(guān)協(xié)議結(jié)構(gòu)應(yīng)用層HTTP,Telnet,F(xiàn)TP等表示層會話層傳輸層TCP,UDP網(wǎng)絡(luò)層IP數(shù)據(jù)鏈路層物理層
了解到HTTP協(xié)議是建立在TCP連接基礎(chǔ)之上的。HTTP 是一種允許瀏覽器向服務(wù)器獲取資源的協(xié)議,是 Web 的基礎(chǔ),通常由瀏覽器發(fā)起請求,用來獲取不同類型的文件, 例如 HTML 文件、CSS 文件、JavaScript 文件、圖片、視頻等。此外,HTTP 也是瀏覽器使用最廣的協(xié)議。
我們對HTTP不太了解的話都會存在這樣的疑惑,為什么再次訪問同一站點會比第一次快,登錄過一次后的網(wǎng)站再次訪問就處于登錄狀態(tài)等,我們 通過對HTTP請求過程的剖析來解開這些謎團(tuán)。
瀏覽器輸入網(wǎng)址:http://time.geekbang.org/index.html,之后會完成什么步驟呢?
首先,瀏覽器構(gòu)建請求行信息,構(gòu)建好后,瀏覽器準(zhǔn)備發(fā)起網(wǎng)絡(luò)請求。
GET /index.html HTTP1.1
在真正發(fā)起網(wǎng)絡(luò)請求之前,瀏覽器會先在瀏覽器緩存中查詢是否有要請求的文件。其中,瀏覽器緩存是一種在本地保存資源副本,以供下次請求時直接使用的技術(shù)。
當(dāng)瀏覽器發(fā)現(xiàn)請求資源已經(jīng)存在瀏覽器緩存中存有副本,則會攔截請求并返回該資源副本結(jié)束請求。如果查找緩存失敗,則會進(jìn)入網(wǎng)絡(luò)請求。所以會有利于:
我們通過開頭預(yù)備知識和前文也大概了解到了HTTP和TCP的關(guān)系。瀏覽器使用 HTTP 協(xié)議作為應(yīng)用層協(xié)議,用來封裝請求的文本信息;并使用 TCP/IP 作傳輸層協(xié)議將它發(fā)到網(wǎng)絡(luò)上,所以在 HTTP 工作開始之前,瀏覽器需要通過 TCP 與服務(wù)器建立連接。也就是說 HTTP 的內(nèi)容是通過 TCP 的傳輸數(shù)據(jù)階段來實現(xiàn)的。
TCP和HTTP的關(guān)系示意圖:
據(jù)此,我們可以知道建立HTTP網(wǎng)絡(luò)請求就是,通過URL地址來解析獲取IP和端口信息,建立服務(wù)器和TCP連接。我們通過前文《TCP協(xié)議》 說到了數(shù)據(jù)包都是通過IP地址傳輸給接收方的。而我們網(wǎng)站一般的地址都是域名,所以需要把域名和IP地址做映射關(guān)系,即解析IP地址的系統(tǒng)“域名系統(tǒng)(DNS)”解析出 IP地址,并獲取對應(yīng)端口號獲得建立連接的前置條件。換句話說,即瀏覽器請求DNS返回域名對應(yīng)的IP,而請求DNS時也會查詢DNS數(shù)據(jù)緩存服務(wù),判斷是否域名已解析過, 如果解析過則查詢直接使用,拿到IP后則判斷URL是否指明端口號,沒有則HTTP協(xié)議默認(rèn)時80端口。
Chrome 有個機(jī)制,同一個域名同時最多只能建立 6 個 TCP 連接,如果在同一個域名下同時有 10 個請求發(fā)生,那么其中 4 個請求會進(jìn)入排隊等待狀態(tài),直至進(jìn)行中的請求完成。當(dāng)然,如果當(dāng)前請求數(shù)量少于 6,會直接進(jìn)入下一步,建立 TCP 連接。
隊列等待結(jié)束后,TCP和服務(wù)器實現(xiàn)“三次握手”(前文TCP協(xié)議有描述),即客戶端和服務(wù)器發(fā)送三個數(shù)據(jù)包以確認(rèn)連接,實現(xiàn)瀏覽器和服務(wù)的連接。
一旦建立了 TCP 連接,瀏覽器就可以和服務(wù)器進(jìn)行通信了。而 HTTP 中的數(shù)據(jù)正是在這個通信過程中傳輸?shù)摹?/p>
HTTP請求數(shù)據(jù)格式:
首先瀏覽器會向服務(wù)器發(fā)送請求行,它包括了請求方法、請求 URI(Uniform Resource Identifier)和 HTTP 版本協(xié)議。
其中請求方式有GET,POST,PUT,Delete等,其中常用的POST會用于發(fā)送一些數(shù)據(jù)給服務(wù)器,比如登錄網(wǎng)站把用戶信息發(fā)送給服務(wù)器,一般 這些數(shù)據(jù)會通過請求體發(fā)送。
在瀏覽器發(fā)送請求行命令之后,還要以請求頭形式發(fā)送其他一些信息,把瀏覽器的一些基礎(chǔ)信息告訴服務(wù)器。比如包含了瀏覽器所使用的操作系統(tǒng)、瀏覽器內(nèi)核等信息,以及當(dāng)前請求的域名信息、Cookie等。
curl -i https://time.geekbang.org/
通過curl工具(或network面板)我們可以了解到服務(wù)器返回的數(shù)據(jù)格式:
首先服務(wù)器會返回響應(yīng)行,包括協(xié)議版本和狀態(tài)碼。
如果出現(xiàn)錯誤,服務(wù)器會通過請求行的狀態(tài)碼來返回對應(yīng)的處理結(jié)果,例如:
正如瀏覽器會隨同請求發(fā)送請求頭一樣,服務(wù)器也會隨同響應(yīng)向瀏覽器發(fā)送響應(yīng)頭。響應(yīng)頭包含了服務(wù)器自身的一些信息, 比如服務(wù)器生成返回數(shù)據(jù)的時間、返回的數(shù)據(jù)類型(JSON、HTML、流媒體等類型),以及服務(wù)器要在客戶端保存的 Cookie 等信息。
響應(yīng)頭之后,服務(wù)器會發(fā)送響應(yīng)體數(shù)據(jù),通常包含了HTML的實際內(nèi)容。以上為服務(wù)器響應(yīng)瀏覽器的過程。
一旦服務(wù)器向客戶端返回了請求數(shù)據(jù),它就要關(guān)閉 TCP 連接。不過如果瀏覽器或者服務(wù)器在其頭信息中加入了:
Connection:Keep-Alive
則TCP 連接在發(fā)送后將仍然保持打開狀態(tài),這樣瀏覽器就可以繼續(xù)通過同一個 TCP 連接發(fā)送請求。保持 TCP 連接可以省去下次請求時需要建立連接的時間,提升資源加載速度。 如果一個頁面內(nèi)嵌的圖片都來自同一web站點,則初始化一個持久連接則可復(fù)用減少TCP的連接。
重定向返回響應(yīng)行和響應(yīng)頭:
狀態(tài) 301 就是告訴瀏覽器,我需要重定向到另外一個網(wǎng)址,而需要重定向的網(wǎng)址正是包含在響應(yīng)頭的 Location 字段中,接下來,瀏覽器獲取 Location 字段中的地址,并使用該地址重新導(dǎo)航,這就是一個完整重定向的執(zhí)行流程。
通過http請求的完整過程,我們就知道,請求過程中DNS緩緩和頁面資源緩存會被瀏覽器緩存起來,以減少向服務(wù)器請求的資源,所以會再次請求站點時速度會快。
瀏覽器資源緩存處理過程:
從上圖的第一次請求可以看出,當(dāng)服務(wù)器返回 HTTP 響應(yīng)頭給瀏覽器時,瀏覽器是通過響應(yīng)頭中的 Cache-Control 字段來設(shè)置是否緩存該資源。通常,我們還需要為這個資源設(shè)置一個緩存過期時長,而這個時長是通過 Cache-Control 中的 Max-age 參數(shù)來設(shè)置的。
因此在該緩存資源還未過期的情況下, 如果再次請求該資源,會直接返回緩存中的資源給瀏覽器。
如果緩存過期了,瀏覽器則會繼續(xù)發(fā)起網(wǎng)絡(luò)請求,并且在 HTTP 請求頭中帶上If-None-Match,服務(wù)器收到請求頭后,會根據(jù) If-None-Match 的值來判斷請求的資源是否有更新。
登錄網(wǎng)站,通過POST方式提交信息給服務(wù)器,服務(wù)器接收到瀏覽器提交的信息之后,查詢驗證信息正確則會生成表面用戶身份的字符串寫入響應(yīng)頭的Set-Cookie字段里返回瀏覽器。
瀏覽器解析響應(yīng)頭,如有Set-Cookie字段則保存在本地,當(dāng)用戶再次訪問時,發(fā)起HTTP請求前瀏覽器會讀取Cookie數(shù)據(jù)并寫入請求頭發(fā)送到服務(wù)器,服務(wù)器再次判斷信息,如果 正確則展示用戶登錄狀態(tài)及用戶信息。
最后總結(jié)出瀏覽器中的HTTP請求從發(fā)起到結(jié)束一共經(jīng)歷了八個階段:構(gòu)建請求、查找緩存、準(zhǔn)備 IP 和端口、等待 TCP 隊列、建立 TCP 連接、發(fā)起 HTTP 請求、服務(wù)器處理請求、服務(wù)器返回請求和斷開連接。
詳細(xì)HTTP請求流程:
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。