目录

前后端交互约定安装创建Axios实例拦截器封装请求方法业务异常处理

axios 是一个易用、简洁且高效的http库 axios 中文文档:http://www.axios-js.com/zh-cn/docs/

前后端交互约定

在本项目中,前后端交互统一使用 application/json;charset=UTF-8 的请求方式,后端返回对象统一为如下格式

export interface ResponseBody {

status: boolean, // 业务处理状态,true表示正常,false表示异常

code: string // 业务处理状态码

message: string, // 提示信息

data?: T // 业务处理返回数据

}

安装

yarn add axios

创建Axios实例

在 src 目录下创建 http 目录,http 请求相关的文件都放置于该目录

创建 axios.ts 文件,用于定义 axios

// axios.ts

const instance: AxiosInstance = axios.create({

baseURL: import.meta.env.VITE_APP_BASE_API,

timeout: 60000,

headers: { 'Content-Type': 'application/json;charset=UTF-8' },

})

其中,import.meta.env.VITE_APP_BASE_API 是 .env 中配置的环境变量,不同环境使用不同的请求地址

拦截器

通过 instance.interceptors.request.use 实现前置拦截器,发起请求前执行,用于对请求对象进行加工处理。

下面这段代码主要做的事情就是将 token 设置到请求头中。

// axios.ts

async function requestHandler(config: InternalAxiosRequestConfig & RequestConfigExtra): Promise {

if (config.modulePrefix) {

config.url = config.modulePrefix + config.url

}

const token = useAuthorization()

if (token.value && config.token !== false) {

config.headers.set("Authorization", token.value)

}

console.log("execute http request:" + config.url)

return config

}

instance.interceptors.request.use(requestHandler)

RequestConfigExtra 为自定义参数,在本项目中定义如下,可根据需要自行扩展。

export interface RequestConfigExtra {

// 模块前缀

modulePrefix?: string,

// 发起请求时,是否需要在请求头中附加 token

token?: boolean,

// 成功处理函数,默认为 false,如果为 false,则什么都不做,如果为 true,则自动提示成功信息,如果为 Function,则自定义处理结果

success?: boolean | ((response: ResponseBody) => void),

// 失败处理函数,默认为 true,如果为 false,则什么都不做,如果为 true,则自动提示失败信息,如果为 Function,则自定义处理结果

error?: boolean | ((response: ResponseBody) => void),

}

通过 instance.interceptors.response.use 实现后置拦截器,对后端返回数据进行处理。

function responseHandler(response: any): ResponseBody | AxiosResponse | Promise | any {

return response.data

}

function errorHandler(errorInfo: AxiosError): Promise {

if (errorInfo.response) {

const { data, status, statusText } = errorInfo.response as AxiosResponse

if (status === 401) {

const token = useAuthorization()

token.value = null

message.error(data?.message || statusText)

router.push({path: '/login', query: {

redirect: router.currentRoute.value.fullPath

}})

} else {

message.error(data?.message || statusText)

}

}

return Promise.reject(errorInfo)

}

instance.interceptors.response.use(responseHandler, errorHandler)

errorHandler 方法对系统异常进行了统一处理,如果后端返回的 status 不是 200,则会执行该处理方法,如果返回 401,表示没有通过登录鉴权,自动跳转登录页,如果是其它异常码,则提示错误信息。

封装请求方法

这里对 restful 常用的四种请求方式进行进一步的封装

// axios.ts

function instancePromise(options: AxiosRequestConfig & RequestConfigExtra): Promise> {

return new Promise((resolve, reject) => {

instance.request>(options)

.then((res) => {

try {

resolve(responseBodyHandle(res, options))

} catch (err) {

reject(err || new Error('response handle error!'))

}

})

.catch((e: Error | AxiosError) => {

reject(e)

})

})

}

export function doGet(url: string, params?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise> {

const options = {

url,

params,

method: RequestEnum.GET,

...config,

}

return instancePromise(options)

}

export function doPost(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise> {

const options = {

url,

data,

method: RequestEnum.POST,

...config,

}

return instancePromise(options)

}

export function doPut(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise> {

const options = {

url,

data,

method: RequestEnum.PUT,

...config,

}

return instancePromise(options)

}

export function doDelete(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise> {

const options = {

url,

data,

method: RequestEnum.DELETE,

...config,

}

return instancePromise(options)

}

业务异常处理

在拦截器中,我们对系统异常进行了统一处理,在实际项目中,更多的情况是前端请求没有通过后端的业务校验,后端返回错误信息,前端进行提示。

创建一个业务异常类

export class ResponseBodyError extends Error {

code: string

message: string

cause: any

constructor({ code, message, cause }: { code: string, message: string, cause?: any }) {

super();

this.code = code;

this.message = message;

this.cause = cause

}

}

实现业务异常统一处理,通过在请求时定义 RequestConfigExtra 中的参数来实现对后端返回结果的提示。

比如:查询请求,设置为 {success:false, error: true},如果请求失败,提示错误信息,如果请求成功,不作处理。业务请求,设置为 {success: true, error: true},如果请求失败,提示错误信息,如果处理成功,提示操作成功。

function responseBodyHandle(response: ResponseBody, options: AxiosRequestConfig & RequestConfigExtra): any {

const { status, message:msg, code, data } = response

const { success, error } = options

if (status === true) {

if (success === true) {

message.success(msg ?? "操作成功")

} else if (isFunction(success)) {

success(response)

}

return response

} else {

if (isFunction(error)) {

error(response)

} else if (error !== false) {

message.error(msg ?? "操作失败")

}

throw new ResponseBodyError({ code, msg })

}

}

完整代码如下:

// axios.ts

/**

* 创建 Axios 实例

*/

const instance: AxiosInstance = axios.create({

baseURL: import.meta.env.VITE_APP_BASE_API,

timeout: 60000,

headers: { 'Content-Type': 'application/json;charset=UTF-8' },

})

/**

* 前置拦截器

*/

async function requestHandler(config: InternalAxiosRequestConfig & RequestConfigExtra): Promise {

if (config.modulePrefix) {

config.url = config.modulePrefix + config.url

}

const token = useAuthorization()

if (token.value && config.token !== false) {

config.headers.set(authorizationHeader, authorizationValue())

}

console.log("execute http request:" + config.url)

return config

}

/**

* 后置拦截器

*/

function responseHandler(response: any): ResponseBody | AxiosResponse | Promise | any {

return response.data

}

/**

* 系统异常统一处理函数

*/

function errorHandler(errorInfo: AxiosError): Promise {

if (errorInfo.response) {

const { data, status, statusText } = errorInfo.response as AxiosResponse

if (status === 401) {

const token = useAuthorization()

token.value = null

message.error(data?.message || statusText)

router.push({path: '/login', query: {

redirect: router.currentRoute.value.fullPath

}})

} else {

message.error(data?.message || statusText)

}

}

return Promise.reject(errorInfo)

}

instance.interceptors.request.use(requestHandler)

instance.interceptors.response.use(responseHandler, errorHandler)

/**

* 业务异常统一处理函数

*/

function responseBodyHandle(response: ResponseBody, options: AxiosRequestConfig & RequestConfigExtra): any {

const { status, message:msg, code, data } = response

const { success, error } = options

if (status === true) {

if (success === true) {

message.success(msg ?? "操作成功")

} else if (isFunction(success)) {

success(response)

}

return response

} else {

if (isFunction(error)) {

error(response)

} else if (error !== false) {

message.error(msg ?? "操作失败")

}

throw new ResponseBodyError({ code, msg })

}

}

function instancePromise(options: AxiosRequestConfig & RequestConfigExtra): Promise> {

return new Promise((resolve, reject) => {

instance.request>(options)

.then((res) => {

try {

resolve(responseBodyHandle(res, options))

} catch (err) {

reject(err || new Error('response handle error!'))

}

})

.catch((e: Error | AxiosError) => {

reject(e)

})

})

}

export function doGet(url: string, params?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise> {

const options = {

url,

params,

method: RequestEnum.GET,

...config,

}

return instancePromise(options)

}

export function doPost(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise> {

const options = {

url,

data,

method: RequestEnum.POST,

...config,

}

return instancePromise(options)

}

export function doPut(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise> {

const options = {

url,

data,

method: RequestEnum.PUT,

...config,

}

return instancePromise(options)

}

export function doDelete(url: string, data?: T, config?: AxiosRequestConfig & RequestConfigExtra): Promise> {

const options = {

url,

data,

method: RequestEnum.DELETE,

...config,

}

return instancePromise(options)

}

相关文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: