- axios的作用
- axios配置文件
- axios在使用中的一些坑
作用
axios其實(shí)就是vue-resourece的一個(gè)更優(yōu)的基于Promise的解決方案临燃,加上vue-resourece早已停止更新睛驳,fetch在配置中又十分的繁瑣烙心,這無(wú)疑讓axios成為我的首選。
配置文件的說(shuō)明
官方文檔其實(shí)已經(jīng)說(shuō)明的很清楚了乏沸,在這里記錄一下淫茵,便于斷網(wǎng)的時(shí)候查詢。
{
// `url` 是用于請(qǐng)求的服務(wù)器 URL
url: '/user',
// `method` 是創(chuàng)建請(qǐng)求時(shí)使用的方法
method: 'get', // 默認(rèn)是 get
// `baseURL` 將自動(dòng)加在 `url` 前面蹬跃,除非 `url` 是一個(gè)絕對(duì) URL匙瘪。
// 它可以通過(guò)設(shè)置一個(gè) `baseURL` 便于為 axios 實(shí)例的方法傳遞相對(duì) URL
baseURL: 'https://some-domain.com/api/',
// `transformRequest` 允許在向服務(wù)器發(fā)送前,修改請(qǐng)求數(shù)據(jù)
// 只能用在 'PUT', 'POST' 和 'PATCH' 這幾個(gè)請(qǐng)求方法
// 后面數(shù)組中的函數(shù)必須返回一個(gè)字符串蝶缀,或 ArrayBuffer丹喻,或 Stream
transformRequest: [function (data) {
// 對(duì) data 進(jìn)行任意轉(zhuǎn)換處理
return data;
}],
// `transformResponse` 在傳遞給 then/catch 前,允許修改響應(yīng)數(shù)據(jù)
transformResponse: [function (data) {
// 對(duì) data 進(jìn)行任意轉(zhuǎn)換處理
return data;
}],
// `headers` 是即將被發(fā)送的自定義請(qǐng)求頭
headers: {'X-Requested-With': 'XMLHttpRequest'},
// `params` 是即將與請(qǐng)求一起發(fā)送的 URL 參數(shù)
// 必須是一個(gè)無(wú)格式對(duì)象(plain object)或 URLSearchParams 對(duì)象
params: {
ID: 12345
},
// `paramsSerializer` 是一個(gè)負(fù)責(zé) `params` 序列化的函數(shù)
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function(params) {
return Qs.stringify(params, {arrayFormat: 'brackets'})
},
// `data` 是作為請(qǐng)求主體被發(fā)送的數(shù)據(jù)
// 只適用于這些請(qǐng)求方法 'PUT', 'POST', 和 'PATCH'
// 在沒(méi)有設(shè)置 `transformRequest` 時(shí)翁都,必須是以下類(lèi)型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 瀏覽器專(zhuān)屬:FormData, File, Blob
// - Node 專(zhuān)屬: Stream
data: {
firstName: 'Fred'
},
// `timeout` 指定請(qǐng)求超時(shí)的毫秒數(shù)(0 表示無(wú)超時(shí)時(shí)間)
// 如果請(qǐng)求話費(fèi)了超過(guò) `timeout` 的時(shí)間碍论,請(qǐng)求將被中斷
timeout: 1000,
// `withCredentials` 表示跨域請(qǐng)求時(shí)是否需要使用憑證
withCredentials: false, // 默認(rèn)的
// `adapter` 允許自定義處理請(qǐng)求,以使測(cè)試更輕松
// 返回一個(gè) promise 并應(yīng)用一個(gè)有效的響應(yīng) (查閱 [response docs](#response-api)).
adapter: function (config) {
/* ... */
},
// `auth` 表示應(yīng)該使用 HTTP 基礎(chǔ)驗(yàn)證柄慰,并提供憑據(jù)
// 這將設(shè)置一個(gè) `Authorization` 頭鳍悠,覆寫(xiě)掉現(xiàn)有的任意使用 `headers` 設(shè)置的自定義 `Authorization`頭
auth: {
username: 'janedoe',
password: 's00pers3cret'
},
// `responseType` 表示服務(wù)器響應(yīng)的數(shù)據(jù)類(lèi)型税娜,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
responseType: 'json', // 默認(rèn)的
// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名稱
xsrfCookieName: 'XSRF-TOKEN', // default
// `xsrfHeaderName` 是承載 xsrf token 的值的 HTTP 頭的名稱
xsrfHeaderName: 'X-XSRF-TOKEN', // 默認(rèn)的
// `onUploadProgress` 允許為上傳處理進(jìn)度事件
onUploadProgress: function (progressEvent) {
// 對(duì)原生進(jìn)度事件的處理
},
// `onDownloadProgress` 允許為下載處理進(jìn)度事件
onDownloadProgress: function (progressEvent) {
// 對(duì)原生進(jìn)度事件的處理
},
// `maxContentLength` 定義允許的響應(yīng)內(nèi)容的最大尺寸
maxContentLength: 2000,
// `validateStatus` 定義對(duì)于給定的HTTP 響應(yīng)狀態(tài)碼是 resolve 或 reject promise 。如果 `validateStatus` 返回 `true` (或者設(shè)置為 `null` 或 `undefined`)藏研,promise 將被 resolve; 否則敬矩,promise 將被 rejecte
validateStatus: function (status) {
return status >= 200 && status < 300; // 默認(rèn)的
},
// `maxRedirects` 定義在 node.js 中 follow 的最大重定向數(shù)目
// 如果設(shè)置為0,將不會(huì) follow 任何重定向
maxRedirects: 5, // 默認(rèn)的
// `httpAgent` 和 `httpsAgent` 分別在 node.js 中用于定義在執(zhí)行 http 和 https 時(shí)使用的自定義代理蠢挡。允許像這樣配置選項(xiàng):
// `keepAlive` 默認(rèn)沒(méi)有啟用
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// 'proxy' 定義代理服務(wù)器的主機(jī)名稱和端口
// `auth` 表示 HTTP 基礎(chǔ)驗(yàn)證應(yīng)當(dāng)用于連接代理弧岳,并提供憑據(jù)
// 這將會(huì)設(shè)置一個(gè) `Proxy-Authorization` 頭,覆寫(xiě)掉已有的通過(guò)使用 `header` 設(shè)置的自定義 `Proxy-Authorization` 頭业踏。
proxy: {
host: '127.0.0.1',
port: 9000,
auth: : {
username: 'mikeymike',
password: 'rapunz3l'
}
},
// `cancelToken` 指定用于取消請(qǐng)求的 cancel token
// (查看后面的 Cancellation 這節(jié)了解更多)
cancelToken: new CancelToken(function (cancel) {
})
}
// 響應(yīng)結(jié)構(gòu)
// 某個(gè)請(qǐng)求的響應(yīng)包含以下信息
{
// `data` 由服務(wù)器提供的響應(yīng)
data: {},
// `status` 來(lái)自服務(wù)器響應(yīng)的 HTTP 狀態(tài)碼
status: 200,
// `statusText` 來(lái)自服務(wù)器響應(yīng)的 HTTP 狀態(tài)信息
statusText: 'OK',
// `headers` 服務(wù)器響應(yīng)的頭
headers: {},
// `config` 是為請(qǐng)求提供的配置信息
config: {}
}
其實(shí)這里的話是要
axios(config)
這樣里面去的想一想這么多的配置文件要一股腦都塞進(jìn)去缩筛,確實(shí)看起來(lái)是非常的不雅而且整個(gè)主代碼會(huì)變得亂七八糟,沒(méi)錯(cuò)堡称,剛開(kāi)始學(xué)習(xí)的我真的這樣做了瞎抛,后期幾乎是完全沒(méi)法維護(hù)的,后來(lái)我通過(guò)學(xué)習(xí)花褲衩大大的代碼却紧,才知道桐臊,這些東西是可以封裝起來(lái)的,大概分出來(lái)兩個(gè)文件晓殊。
首先是axios的配置文件(需要自己創(chuàng)建哦我個(gè)人是命名為request.js并且丟在src的utils文件夾中自己建的)
import axios from 'axios'
// axios配置信息
axios.defaults.withCredentials = true
const service = axios.create({
baseURL: process.env.BASE_API, // api 的 前綴url
timeout: 5000, // 請(qǐng)求超時(shí)
})
// 數(shù)據(jù)發(fā)送前的攔截器
service.interceptors.request.use(
config => {
return config
},
error => {
Promise.reject(error)
}
)
// 數(shù)據(jù)接受時(shí)的攔截器
service.interceptors.response.use((response) => {
return response
}, (err) => {
switch (err.response.status) {
case 500:
break;
case 429:
break;
default:
}
})
export default service
- 首先是這個(gè)配置文件断凶,在
axios.create
這個(gè)方法中,有baseURL和timeout
這兩個(gè)配置巫俺,前者指向的是webpack
的開(kāi)發(fā)環(huán)境和生產(chǎn)環(huán)境认烁,這個(gè)如果有自己配置的話,就在里面加一個(gè)baseURL
即可介汹,如果還不清楚的話却嗡,建議通過(guò)console
來(lái)查看具體位置;再下面就是有兩個(gè)攔截器嘹承,一個(gè)是數(shù)據(jù)發(fā)送前窗价,一個(gè)是數(shù)據(jù)接受時(shí),這兩個(gè)攔截器用處很大叹卷,我這么配置之后撼港,基本一目了然,在下面的res攔截器中骤竹,可以捕獲到http錯(cuò)誤碼帝牡,可以通過(guò)判斷和后端的錯(cuò)誤碼來(lái)給予用戶最人性化的提示。- 而在數(shù)據(jù)發(fā)送前的這個(gè)攔截器則可以統(tǒng)一配置
header
等這一系列的東西從而避免在主代碼中去重新設(shè)置這些東西蒙揣,比如使用qs去轉(zhuǎn)換需要發(fā)送的數(shù)據(jù)對(duì)吧靶溜,很方便的。
請(qǐng)求地址配置文件(同樣是需要自己創(chuàng)建我個(gè)人是新建了一個(gè)目錄api鸣奔,然后把它放入新加的js文件中)
// 在此處導(dǎo)入之前配置的service
import request from 'request'
export default {
// 內(nèi)容為請(qǐng)求的函數(shù)墨技,例如:
post(data) {
return request({
url: "",
method: "post",
data
})
},
get(params) {
return request({
url: "",
method: "get",
params
})
},
}
這里的請(qǐng)求配置文件就很明了了惩阶,導(dǎo)入之后使用
export default
將其中的函數(shù)全部暴露出去方便調(diào)用,而函數(shù)內(nèi)則是這樣的一個(gè)結(jié)構(gòu)扣汪,在函數(shù)內(nèi)部配置一個(gè)url,method,data
断楷,為什么要將這些配置分離出來(lái)配置而不是在之前的配置文件中使用,因?yàn)榉?wù)端提供的接口方式多是多樣崭别,可以是get,post,put,dele
其中的任意一個(gè)冬筒,而url則是前面相同部分的服務(wù)器地址后面的接口地址那部分,聽(tīng)起來(lái)是不是有點(diǎn)繞茅主?舉個(gè)栗子:現(xiàn)在有兩個(gè)接口舞痰,https://skyserver.com/get_list 和 https://skyserver.com/get_list 那么我就可以設(shè)baseURL為 https://skyserver.com,而這里的url則是/get_list
或者是/get_list
诀姚,明白了嗎响牛?每一個(gè)接口我們只需要更改后面的接口名和請(qǐng)求方式就好了。
如何去使用赫段?
emm呀打,其實(shí)使用方法有很多,我個(gè)人推薦是去
main.js
文件中去引入糯笙,例如我引入之后的名字是api那么我就可以使用這行代碼Vue.prototype.$api = api
意思為將這個(gè)掛載到vue的原型中去贬丛,這樣的好處就是我們可以直接使用this.$api.get()
的方式進(jìn)行調(diào)用,由于axios本身就是一個(gè)基于Promise
的項(xiàng)目给涕,其實(shí)就可以直接使用async and await
的形式來(lái)進(jìn)行調(diào)用豺憔,借助webpack
的一部分功能讓自己的代碼本體變得不再那么冗余。
踩過(guò)的坑
- axios本身不會(huì)發(fā)送cookie够庙,需要你自己加上
axios.defaults.withCredentials = true
這句代碼才會(huì)發(fā)送cookie恭应,但是會(huì)存在跨域問(wèn)題澳厢,在這里由于我只使用了nodejs作為后端所以只舉例nodejs如何解決這個(gè)跨域問(wèn)題的:
首先我使用的是的是express框架茄靠,不過(guò)影響不大,畢竟koa和其他的都是差不多的原理。話不多說(shuō)先上代碼:
// 我們可以直接獲取訪問(wèn)服務(wù)器的來(lái)源直接賦值過(guò)去毅桃,雖然方便,但是要知道本身這個(gè)是防御XSS攻擊准夷,這么設(shè)置之后的風(fēng)險(xiǎn)閱讀者應(yīng)該要須知钥飞。
let origin = req.header.origin
//訪問(wèn)控制允許來(lái)源,有人會(huì)問(wèn)為什么這里不是一個(gè)'*'呢衫嵌,因?yàn)樵趩⒂昧薱ookie之后读宙,是不允許使用通配符的,所以在當(dāng)需要發(fā)送cookie的場(chǎng)景中
res.header('Access-Control-Allow-Origin', origin);
//訪問(wèn)控制允許報(bào)頭 X-Requested-With: xhr請(qǐng)求
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept,X-Token");
//訪問(wèn)控制允許方法
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
// 它的值是一個(gè)布爾值楔绞,表示是否允許發(fā)送Cookie结闸。默認(rèn)情況下唇兑,Cookie不包括在CORS請(qǐng)求之中。設(shè)為true桦锄,即表示服務(wù)器明確許可扎附,Cookie可以包含在請(qǐng)求中,一起發(fā)給服務(wù)器结耀。這個(gè)值也只能設(shè)為true留夜,如果服務(wù)器不要瀏覽器發(fā)送Cookie,刪除該字段即可图甜。
res.header("Access-Control-Allow-Credentials",true);
//自定義頭信息碍粥,表示服務(wù)端用nodejs,其實(shí)你也可以發(fā)送其他的2333雖然意義不明
res.header('X-Powered-By', 'nodejs');
// 定義發(fā)送的數(shù)據(jù)格式
res.header('Content-Type', 'application/json;charset=utf-8');
這里出現(xiàn)的弊端黑毅,想必一眼就看出來(lái)了對(duì)嗎嚼摩?這里允許了所有來(lái)訪者的url,但是事實(shí)上我們并不能這樣允許矿瘦,因?yàn)檫@樣是有安全問(wèn)題的低斋!so,做個(gè)判斷不就好啦:
// 這里規(guī)定一個(gè)白名單匪凡,允許哪些域名訪問(wèn)膊畴,是一個(gè)數(shù)組
let whitList = ['','']
// 這里則使用的是es6的語(yǔ)法,檢查該變量是否存在于數(shù)組中
// 和es5中的 `indexOf()` 有異曲同工之妙病游,但是它返回的是一個(gè)布爾值唇跨,除了不能夠定位元素的位置,但是用在此處很棒不是么~
if(whitList.includes(origin)){
// 這里是上面的那段代碼
}
- axios是基于es6語(yǔ)法的衬衬,你可能會(huì)遇到
Promise is not function
的問(wèn)題买猖,通常出現(xiàn)在老舊瀏覽器上,可以通過(guò)bable來(lái)進(jìn)行轉(zhuǎn)換滋尉。下圖是其瀏覽器的支持玉控。
Latest ? | Latest ? | Latest ? | Latest ? | Latest ? | 11 ? |
- 它攔截接收?qǐng)?bào)錯(cuò)的信息是在
err.response
中,而不是直接的err就可以獲取到狮惜,這一點(diǎn)是很坑的高诺,一直以來(lái)我都以為是在err中,導(dǎo)致始終無(wú)法捕捉到http狀態(tài)值以及報(bào)錯(cuò)信息碾篡,其實(shí)官方文檔也有說(shuō)明虱而,如果我不是那么的星際也不會(huì)犯這種低級(jí)錯(cuò)誤