Vue3+Vite+ts 从零开发前端 – 9 – 封装 API
本文最后更新于 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, DELETEPATCH 使用 data 参数

const login = async (data: LoginParam) => post({ url: URL.login, data })
版权声明:除特殊说明,博客文章均为Gavin原创,依据CC BY-SA 4.0许可证进行授权,转载请附上出处链接及本声明。
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇