登录
Axios 支持浏览器和服务端进行 ajax 请求。
基本的 Axios 使用,和 jquery 差不多。
安装:
npm install -S axios
以下几个语法,都能发出请求,且返回值为一个 Promise:
import Axios from 'axios'
(async () => {
let res = await Axios(url[, config])
let res = await Axios.request(config)
let res = await Axios.get(url[, config])
let res = await Axios.delete(url[, config])
let res = await Axios.head(url[, config])
let res = await Axios.options(url[, config])
let res = await Axios.post(url[, data[, config]])
let res = await Axios.put(url[, data[, config]])
let res = await Axios.patch(url[, data[, config]])
})()
且可以为 Axios 添加一些全局的默认配置,一次执行,即使在其他文件中再使用 Axios,也同样生效:
import Axios from 'axios'
// 配置默认配置
Axios.defaults.baseURL = 'http://localhost:1213'
Axios.defaults.headers = {'content-type': 'application/json;charset=utf-8'}
(async () => {
let res = await Axios('/getNameGet')
})()
后面这个 config 的配置项很多,常用的添加参数、添加消息体等常用选项,都在其中配置:
const config = {
baseURL: 'http://localhost:1213',
method: 'post', // 默认 get 请求
headers: {'a-b': 'XMLHttpRequest'},
url: '/getNamePost',
responseType: 'json', // 响应的格式
// 请求体数据
data: {
firstName: 'Fred'
},
// 即将与请求一起发送的,以 ? 和 & 拼接在 URL 中的参数
params: {
a: 100
},
// timeout: 1000 * 60, // 超时,毫秒
// 请求前拦截,只能用在 'PUT', 'POST' 和 'PATCH' 这几个请求方法
// 必须返回一个字符串,或 ArrayBuffer,或 Stream
transformRequest: [function (data, headers) {
// 对 data 进行任意转换处理
return data;
}],
// 响应后拦截
transformResponse: [function (data) {
// 对 data 进行任意转换处理
return data;
}],
// 负责 `params` 序列化的函数
// paramsSerializer: function(params) {
// return Qs.stringify(params, {arrayFormat: 'brackets'})
// },
// 表示跨域请求时是否需要使用凭证...发送请求时,是否带 cookie
// withCredentials: false, // default
// `adapter` 允许自定义处理请求,以使测试更轻松
// 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).
// adapter: function (config) {
// /* ... */
// },
// 服务器响应的数据类型,可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
// 响应的编码
// responseEncoding: 'utf8', // default
// 定义允许的响应内容的最大长度
// maxContentLength: 2000,
// 'proxy' 定义代理服务器的主机名称和端口
// `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
// 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
// proxy: {
// host: '127.0.0.1',
// port: 9000,
// auth: {
// username: 'mikeymike',
// password: 'rapunz3l'
// }
// },
// `cancelToken` 指定用于取消请求的 cancel token
// cancelToken: new CancelToken(function (cancel) {
// })
}
可以全局创建一个 Axios 服务,对这个服务初始化一些统一的配置和统一的拦截。
如代码示例,分三个部分:
request.js 中:
// import Cookies from 'js-cookie';
import Axios from 'axios';
// 创建一个 axios 服务
const service = Axios.create({
// 默认配置们
baseURL: 'http://localhost:1213',
timeout: 1000 * 60, // 超时时间, 毫秒
// withCredentials: true, // 发送请求时,是否带 cookie
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
})
/**
* 请求拦截
*/
service.interceptors.request.use(config => {
// 自动添加请求头
// if (Cookies.get('token')) {
// config.headers['Authorization'] = `Bearer ${Cookies.get('token')}`
// }
// 对请求体的参数,进行处理
// if (config.method.toUpperCase() === 'GET') { // get 请求的参数在 params 字段中
// config.params = config.params || {}
// config.params.type = 'get'
// }
// if (config.method.toUpperCase() === 'POST') { // post 请求的参数在 data 字段中
// config.data = config.data || {}
// config.data.type = 'get'
// }
return config;
}, Promise.reject)
/**
* 响应拦截
* 发起请求时,可在 url、method、data 的同级传入参数,用来配置得到响应后的处理
*/
service.interceptors.response.use(async response => {
return await getResponse(response)
}, async err => {
// 打印错误
console.error(err)
if (err.response) return await getResponse(err.response)
// 超时
if (err?.message?.includes('timeout')) {
Message.error('服务器连接失败') // 请求超时
} else if (err?.message?.includes('Network Error')) { // 网络错误
Message.error('网络连接失败') // 网络错误
} else {
Message.error('服务出错,请稍后再试!')
}
return [false, null, err]
})
// 返回结果的处理程序
async function getResponse(response) {
const {
handle = true, // 进行参数的 code 和其他处理?
tip = true, // 接口返回 code 非正常时,自动弹出错误提示?
// reloadFun = null, // 重新调用该接口时,需要掉这个方法拿到新的配置(主要是 token 放在参数里了,需要重新获取)
} = response.config || {}
let success = null, data = null
// 进行数据预处理再返回给调用者
if (handle) {
const allData = response.data
if (!allData) {
success = false
console.error('后台没有返回数据', response)
if (tip) message.error('无数据响应')
} else {
success = allData.code === 0
if (success) {
data = allData.data
} else {
// success 为 false 的处理
data = allData
// if (response.data && response.data.code === 401) { // 401, token失效
// clearLoginInfo() // 清除用户token
// router.push({ name: 'login' }) // 其他操作
// }
// 未登录或 token 过期
// if ([11013, 11014, 11015, 11016].includes(allData.code)) {
// // 刷新 token
// let [isSuccess] = await store.dispatch('auth/refreshToken')
// // 刷新 token 成功,直接再去调刚才这个接口
// if (isSuccess) return reloadFun ? reloadFun() : $axios(response.config)
// else await store.dispatch('auth/logout', false)
// }
if (tip) { // 需要弹框提醒
if (allData.msg && typeof(allData.msg) === 'string') Message.error(allData.msg)
else Message.error('接口服务出错')
}
}
}
}
return [success, data, response]
}
export default service;
默认情况,网站与接口同域,则调用接口时自带携带 cookie,如果网站与接口不是同一域名,则不携带。
但当非同一域名时,仍然想携带 cookie,需把配置项 withCredentials 设置为 true,同时后台的响应头需要做一些处理:
以下为 node 的服务端设置响应头的代码:
response.setHeader('Access-Control-Allow-Origin', request.headers.origin) // 允许跨域的请求头
response.setHeader('Access-Control-Allow-Headers', 'content-type,all,h-common,h-post,h-get')
response.setHeader('Access-Control-Allow-Credentials', 'true')
api.js 文件中:
// 引入上面那个服务
import service from './request'
export const getNameGet = (data) => (
// get 获取 name
service({
url: '/getNameGet',
method: 'get',
params: data,
})
);
export const getNamePost = (data) => (
// post 获取 name
service({
url: '/getNamePost',
method: 'post',
data,
})
);
某个页面:
// 引入接口
import { getNameGet, getNamePost } from './api'
// 在 async 异步函数中使用(或者使用 Promise,不再距离)
(async function() {
try {
// 使用 await,这里是请求成功,也就是 Axios 服务中,没有使用 Promise.reject 返回的结果
let result = await getNameGet({a: 10, b: 20})
console.log(result)
} catch (error) {
// Axios 服务中,使用 Promise.reject 返回的结果,走这里
console.log(error)
}
try {
let result = await getNamePost({a: 10, b: 20})
console.log(1, result)
} catch (error) {
console.log(2, error)
}
})()
有一些特殊接口,当它出错时,我们不希望它和其他接口一样,弹出统一提示,而且希望偷摸去做一些其他事。
可以在写 api 时,写入一些参数:
api.js 文件中:
// 引入上面那个服务
import service from './request'
export const getNameGet = (data, toBack = false) => (
service({
url: '/getNameGet',
method: 'get',
params: data,
notTip: true, // 自定义参数
toBack, // 调用接口时临时配置
})
);
request.js 中:
以下能拿到数据,自然就能自己根据判断,去做一些其他处理。
// 其他代码...
// 请求前的拦截
service.interceptors.request.use(config => {
console.log(config.notTip) // 拿到数据
console.log(config.toBack) // 拿到数据
// 其他代码...
return config;
}, Promise.reject)
// 响应后的拦截
service.interceptors.response.use(res => {
console.log(res.config.notTip) // 拿到数据
console.log(res.config.toBack) // 拿到数据
// 其他代码...
return Promise.reject(res)
}, err => {
console.log(err.config.notTip) // 拿到数据
console.log(err.config.toBack) // 拿到数据
// 其他代码...
return Promise.reject(err)
})
// 其他代码...
无论是Vue还是React,使用了Axios后,在某些时候,需要停止已经发出、正在pedding等待响应的接口,比如在跳页时。
下面就是Vue在跳页时紧急停止axios接口调用的方法,React同理。
但虽说前端停止了接口调用,但如果后台已经处理完了这个接口的数据和操作,那还是无法撤回的。
// store.js 存放某处的全局变量
export const store = {
source: {
token: null,
cancel: null
}
}
// axios 配置中
import store from '@/store.js'
http.interceptors.request.use(config => {
config.cancelToken = store.source.token
return config
}, err => {
return Promise.reject(err)
})
// router的配置文件中
import Axios from 'axios';
import store from '@/store.js'
router.beforeEach((to, from, next) => {
const CancelToken = Axios.CancelToken
store.source.cancel && store.source.cancel()
store.source = CancelToken.source()
next()
})