本文最后更新于 297 天前,如有失效请评论区留言。
前言
前端 http 请求,我们使用最流行的 axios 库,资源比较多,成熟稳定
安装 axios
npm install axios
axios 基本使用
方式1
默认的写法,将 axios 作为函数的形式进行调用,这种方式使用默认的 axios 实例,即使用默认的实例配置
// 发起一个post请求
axios({
method: 'get',
url: 'http://bit.ly/2mTM3nY',
responseType: 'stream'
})
.then(function (response) {
response.data.pipe(fs.createWriteStream('ada_lovelace.jpg'))
});
也可以直接调用对用的请求方法,例如发送 post 请求
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
方式2
1、创建 axios 实例对象
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
2、设置拦截器,在请求和响应时做一些通用的处理
请求和响应拦截器都是一个个函数,在 axios 实例上进行自定义
// 添加请求拦截器
instance.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
instance.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});
3、请求调用
使用 axios 实例调用请求方法,常用的 get、post 方法都有
instance.get('/user/detail'),
4、响应,json 格式包含下面这些属性
{
// `data` 由服务器提供的响应
data: {},
// `status` 来自服务器响应的 HTTP 状态码
status: 200,
// `statusText` 来自服务器响应的 HTTP 状态信息
statusText: 'OK',
// `headers` 是服务器响应头
// 所有的 header 名称都是小写,而且可以使用方括号语法访问
// 例如: `response.headers['content-type']`
headers: {},
// `config` 是 `axios` 请求的配置信息
config: {},
// `request` 是生成此响应的请求
// 在node.js中它是最后一个ClientRequest实例 (in redirects),
// 在浏览器中则是 XMLHttpRequest 实例
request: {}
}
对应的 axios response 响应的源码
export interface AxiosResponse<T = any, D = any> {
data: T;
status: number;
statusText: string;
headers: RawAxiosResponseHeaders | AxiosResponseHeaders;
config: InternalAxiosRequestConfig<D>;
request?: any;
}
data 是一个泛型,这里就可以自己去定义 data 的返回信息
Vue 中封装 axios
添加请求和响应拦截器,处理一些常见的响应信息
import axios from 'axios'
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse, AxiosError, InternalAxiosRequestConfig } from 'axios'
import { ApiResponse, resolveResError } from './common'
import { TokenPrefix, getToken } from '@/utils/auth'
const service: AxiosInstance = axios.create({
baseURL: import.meta.env.APP_API_BASEURL,
timeout: 1000
})
/** 请求拦截处理 */
function reqResolve(config: InternalAxiosRequestConfig) {
// 处理不需要token的请求
const accessToken = getToken()
if (accessToken) {
config.headers.authorization = TokenPrefix + accessToken
}
return config
}
function reqReject(error: AxiosError) {
return Promise.reject(error)
}
/** 响应拦截处理 */
function resResolve(response: AxiosResponse) {
const { data, status, statusText } = response
if (status === 200) {
return Promise.resolve(data)
} else {
// 处理自定义 code 异常信息
const code = data?.code ?? status
const message = resolveResError(code, data?.message ?? statusText)
window.$message?.error(message)
return Promise.reject({ code, message, error: data ?? response })
}
}
function resReject(error: AxiosError) {
if (!error || !error.response) {
const code = error?.code
/** 根据code处理对应的操作,并返回处理后的message */
const message = resolveResError(code, error.message)
window.$message?.error(message)
return Promise.reject({ code, message, error })
}
let code = error.response?.status
let message = error.message
message = resolveResError(code, message)
/** 需要错误提醒 */
window.$message?.error(message)
return Promise.reject({
code,
message,
error: error.response?.data || error.response
})
}
service.interceptors.request.use(reqResolve, reqReject)
service.interceptors.response.use(resResolve, resReject)
/**
*
* @param config
* @returns
*/
const request = <T = any>(config: AxiosRequestConfig): Promise<T> => {
const conf = config
return new Promise((resolve) => {
service.request<any, AxiosResponse<ApiResponse>>(conf).then((res: AxiosResponse<ApiResponse>) => {
const {
data: { result }
} = res
resolve(result as T)
})
})
}
export function get<T = any>(config: AxiosRequestConfig): Promise<T> {
return request({ ...config, method: 'GET' })
}
export function post<T = any>(config: AxiosRequestConfig): Promise<T> {
return request({ ...config, method: 'POST' })
}
export function put<T = any>(config: AxiosRequestConfig): Promise<T> {
return request({ ...config, method: 'put' })
}
export function del<T = any>(config: AxiosRequestConfig): Promise<T> {
return request({ ...config, method: 'delete' })
}
export default request
API 调用
关于用户的登入登出操作,新建 api/user 目录
index.ts
import { get, post } from '@/utils/http'
enum URL {
login = '/user/login',
logout = '/user/logout'
}
interface LoginRes {
token: string
}
export interface LoginParam {
username: string
password: string
}
const login = async (data: LoginParam) => post({ url: URL.login, data })
const logout = async () => post<LoginRes>({ url: URL.logout })
export { login, logout }
对于 axios.request 方法,封装的 api 中参数传递有固定写法
GET
请求使用 params
参数
const getProductList = async (params: {catId:number}) => get<Product[]>({ url: URL.productList, params })
PUT
, POST
, DELETE
和 PATCH
使用 data
参数
const login = async (data: LoginParam) => post({ url: URL.login, data })