1.0.0 • Published 3 years ago

lcs-axios v1.0.0

Weekly downloads
-
License
ISC
Repository
-
Last release
3 years ago

@lcs/http

基于 axios 进行二次封装,更简单、更统一地使用 axios。

核心类 @/utils/http/request 为方便,统一将@/utils/http/request 用lcsAxios表示

功能列表

  1. 封装调用方式统一的 GET/POST/PUT/DELETE/FORMDATA 方法
  2. 自定义接口调用失败时如何处理错误提示(可开关,支持全局开关和单个接口开关)
  3. 常见 HTTP 状态码的中英文提示 400/401/403/404/405/413/414/500/502/504(可配置) netErrorTip(boolean) netErrorTipFn(function)
  4. 自定义错误处理函数,可以根据状态码指定不同错误类型的自定义操作:如 403 跳转到指定页面 app内401作登录跳转
  5. hooks 方法 beforeHook(config) 接口请求前自定义操作:如可以在请求时给页面添加蒙层,加载中效果 afterHook(responce/error, isError) 接口返回后自定义操作:如取消 loading 效果、处理返回数据的数据结构等
  6. 兼容错误信息在 200 请求情况 指定获取状态码函数 getResStatus(resData),获取 response 中的错误码 指定获取错误消息函数 getResErrMsg(resData),获取 response 中的错误消息 指定获取返回最终数据函数 getResData(resData),获取 response 中的返回数据
  7. 兼容 200 情况下的错误统一处理(可配置)如:-1001 -703 -701 app内跳转到登录页面判断 支持全局开关和当个接口开关 codeErrorTip(boolean) codeErrorTipFn(function)
  8. validateStatus自主校验接口状态
  9. 配置可取消重复请求
  • 在 new LcsAxios 实例时,配置cancelDuplicated: true可开启取消重复的请求
  • 在 new LcsAxios 实例时,duplicatedKeyFn函数可配置统一的重复请求的标识
  • 在请求时可自定义配置单个请求的重复标识duplicatedKey
  • 在请求时可自定义配置单个请求的cancelDuplicated: true可开启取消重复的请求
  1. create axios默认参数,支持传入axiosConfig覆盖
    {
      timeout: 8000,
      responseType: 'json',
      headers: {
        'content-type': 'application/x-www-form-urlencoded'
      }
    }
  2. 支持配置一些需要自动带入在接口参数中的全局参数 如platform 如全局参数和接口参数发送冲突,以接口参数为主

使用方式

import Request from './request'
import config from '@/config'
import getHeader from './header'
import errorHandlers from './errorHandlers'
// eslint-disable-next-line no-unused-vars
import { Dialog } from 'vant'
const platform = process.env.VUE_APP_INSURE_PLATFORM
const lcsAxiosConfig = {
  errorHandlers,
  cancelDuplicated: false,
  codeErrorTipFn: (msg) => {
    Dialog.alert({
      title: '提示',
      message: msg
    })
  }
}
const axiosConfig = {
  baseURL: config.baseApi,
  timeout: 8000,
  headers: getHeader()
}

const request =  new Request(lcsAxiosConfig, axiosConfig)

export default {
  list: (params) => request.get('/user', params),
  add: (params) => request.post('/user', params),
  update: (id, params) => request.put(`/user/${id}`, params),
  delete: (id) => request.delete(`/user/${id}`),
  deletes: (params) => request.delete(`/user/`, params),
  upload: (params) => request.formdata(`/user/`, params),
}

lcsAxiosConfig 支持以下配置:

      // 请求报错提示
      // 这里将net错误和code错误分开
      netErrorTip = true,
      netErrorTipFn = (message) => { console.error(message) },
      // code错误是否提示
      codeErrorTip = true,
      // 报错提示函数
      codeErrorTipFn = (message) => { console.error(message) },
      errorHandlers = {
        // 错误回调 response.status  response.data.code
        // 支持 400/401/403/404/405/413/414/500/502/504/任意其他 errno
        // 401: () => {}
        // 403: () => {}
        // ...
      },
      // error msg language: 'zh-cn'/'en'
      lang = 'zh-cn',
      // 接口发送之前
      beforeHook,
      // 接口发送之后
      afterHook,
      // 获取接口的请求状态码。 -code
      getResStatus,
      // 或者接口的错误提示信息  -msg
      getResErrMsg,
      // 获取接口返回数据
      getResData,
      // 校验接口状态码
      validateStatus,

      // 是否取消重复请求
      cancelDuplicated = true,

      // 如果开启了取消重复请求,如何生成重复标识p
      duplicatedKeyFn,

LcsAxios 实例支持 get/post/put/delete/formdata实例方法,并且调用方式统一。

  request.get(path, params, config)
  request.post(path, params, config)
  request.put(path, params, config)
  request.delete(path, params, config)
  request.formdata(path, params, config)
  path 为请求路径;
  params 为请求参数,GET/FORMDATA 的参数也不用特殊处理,lcs-axios 会统一处理,其中formdata的 Content-Type 为 multipart/form-data;charset=UTF-8

自定义错误提示函数

当接口报错时,我们通常会对错误信息进行提示。LcsAxios 提供了统一的方式来处理错误消息。在 LcsAxiosConfig 中指定 netTipFn(errmsg) 和 codeTipFu(errmsg) 可以指定错误消息的处理方式,指定 netTip(布尔值、codeTip(布尔值)可以开关是否执行错误提示。

const request = new LcsAxios({
  tipFn: () => alert
})

支持当个接口禁用tip

// 禁用 tip
request.get(path, params, {  disableTip: true })

Tip:这里很重要。如果在errorHandlers中存在相应错误码的处理函数,则tipFn失效,优先使用errorHandlers中的处理函数,某些场景下我们需要对错误进行弹窗后处理,就需要用到errorHandlers 如:-1001 401 -703 -701

自定义错误处理函数

使用 axios 进行接口请求发生错误时,一般会有两种,一种是validateStatus不通过时(默认是 2xx 通过) ,另一种是所有接口错误信息都由 200 状态返回,返回结果中带有固定字段表示,如 code/msg

在接口请求的过程中,我们有时会需要对于对某些特殊的错误进行一些额外的操作,如 403 的时候跳转到无权限的错误提示页。

这时候,我们可以在配置中添加相应的错误处理函数errorHandlers,可以给不同的错误码指定不同的处理函数,并且支持自定义的 errorCode。

// request.js
const request = new VeryAxios({
  errorHandlers: {
    // 支持 400/401/403/404/405/413/414/500/502/504/任意其他 errno
    401: () => {}
    403: () => {}
    // 任意自定义errno
    1002: () => {}
  },
})

禁用错误处理

request.get(path, params, {  disableHandler: true })

Hooks

lcsAxios 在请求前和请求后都留了钩子,以备需要在这两个时机进行特殊的处理。

  • beforeHook(config) 接口请求前的钩子函数

    在接口请求前触发,可以在请求时给页面添加蒙层,加载中效果。config参数是最后发送请求时的配置。

config 为引用传值,可以对该引用的值进行修改,修改后会影响提交的配置

  • afterHook(responce/error, isError) 接口返回后钩子函数

    在接口请求返回后触发,可以进行取消 loading 效果、处理返回的数据结构等操作。其中第一个参数在请求成功时是接口返回的响应response,在接口失败时,是返回的错误对象。第二个参数标识是否是错误返回。

    response 为引用传值,可以对该引用的值进行修改,如对返回的数据结构进行调整

    通常我们会在实例化时进行通用的钩子函数定义。但可能存在某些特殊的请求,不需要执行 hooks,这时候我们可以在单独的请求中,指定是否禁用 hooks 以及禁用哪一个 hooks。

      // 禁用全部 hooks
      request.GET(path, params, { veryConfig: { disableHooks: true } })
    
      // 禁用 before hooks
      request.GET(path, params, { veryConfig: { disableHooks: { before: true } } })
    
      // 禁用 afater hooks
      request.GET(path, params, { veryConfig: { disableHooks: { after: true } } })

配置可取消重复请求自动

如果开启了取消重复请求,但是没有配置duplicatedKeyFnduplicatedKey,那么默认的重复请求标识为:${config.method}${config.url}。如果同时配置了duplicatedKeyFnduplicatedKey,那么duplicatedKey的优先级高于duplicatedKeyFn

在 new LcsAxios 实例时,配置cancelDuplicated: true可开启取消重复的请求

  const lcsAxiosConfig = {
    cancelDuplicated: true,
  }
  const request = new LcsAxios(veryAxiosConfig)

在 new LcsAxios 实例时,duplicatedKeyFn函数可配置统一的重复请求的标识

  const lcsAxiosConfig = {
    cancelDuplicated: true,
    duplicatedKeyFn: (config) => {
      const { method, url, responseType } = config
      return `${method}${url}${responseType}`
    }
  }
  const request = new LcsAxios(lcsAxiosConfig)

在请求时的可自定义配置单个请求的重复标识duplicatedKey

  request.get(path, params, {  duplicatedKey: 'duplicatedKey'  })

自定义错误信息及数据的获取

接口在返回错误时有两种常见方案,其中一种是全部 200 返回,通过特定字段标识是否是错误,如 code, 表示错误号,非 0 则为错误;msg 表示错误信息;data 为返回的数据。这也是 LcsAxios 的默认值。 有些时候,接口并非我们预想的这样统一,我们可以通过以下三个函数分别指定如何从 reponse data 中获取上述的三个值。

  • getResStatus(resData),获取 response 中的错误码,默认值 (resData) => resData.code
  • getResErrMsg(resData),获取 response 中的错误消息,默认值 (resData) => resData.msg
  • getResData(resData),获取 response 中的返回数据,默认值 (resData) => resData.data

踩坑记录: 1.ajax发送json数据时设置contentType: "application/json”和不设置时到底有什么区别? contentType: "application/json”,首先明确一点,这也是一种文本类型(和text/json一样),表示json格式的字符串,如果ajax中设置为该类型,则发送的json对象必须要使用JSON.stringify进行序列化成字符串才能和设定的这个类型匹配。同时,对应的后端如果使用了Spring,接收时需要使用@RequestBody来注解,这样才能将发送过来的json字符串解析绑定到对应的 pojo 属性上。另外,需注意一点,json字符串在书写时名称部分需要加上“”双引号,以免一些json解析器无法识别。

如ajax 请求时不设置任何contentType,默认将使用contentType: "application/json”application/x-www-form-urlencoded,这种格式的特点就是,name/value 成为一组, 每组之间用 & 联接,而 name与value 则是使用 = 连接。如: www.baidu.com/query?user=username&pass=password 这是get请求, 而 post 请求则是使用请求体,参数不在 url 中,在请求体中的参数表现形式也是: user=username&pass=password的形式。使用这种contentType时,对于简单的json对象类型,如:{“a”:1,"b":2,"c":3} 这种,将也会被转成user=username&pass=password 这种形式发送到服务端。而服务端接收时就按照正常从from表单中接收参数那样接收即可,不需设置@RequestBody之类的注解。但对于复杂的json 结构数据,这种方式处理起来就相对要困难,服务端解析时也难以解析,所以,就有了application/json 这种类型,这是一种数据格式的申明,明确告诉服务端是什么格式的数据,服务端只需要根据这种格式的特点来解析数据即可。

2.post要将参数放在 config.data中!get请求参数为config.params。

3.在axios封装过程中,为了兼容不同平台的api,故在核心类request.js中不掺杂任何的业务代码,都是由外部传入。不同平台的api如果互相不兼容,则需要各种实例化request类。这次封装,旨在在多人协作上,摒弃copy代码式玩法,统一api封装风格,统一前端报错提示,统一用户体验。

LcsAxios 实例化参数

属性说明类型默认值备注
netErrorTipFn接口状态非200报错回调函数Function(message) => { console.error(message) }-
netErrorTip是否接口状态非200执行netErrorTipFnBooleantrue-
codeErrorTipFn返回参数 code 非0报错回调函数Function(message) => { console.error(message) }-
codeErrorTip是否返回参数 code 非0报错回调函数Function(message) => { console.error(message) }-
lang错误提示中音文Stringzh-cn-
beforeHook接口发送之前处理函数,参数axios.configFunction(config) => log(config)在该hook中可带入一些全局参数,如platform,headers中的access-token
afterHook接口发送之前处理函数,参数responseFunctionres => {}-
errorHandlers错误码回调函数集合Object{}-
getResStatus获取接口返回参数状态标示Functionres => res.code-
getResErrMsg获取接口的错误提示信息Functionres => res.msg-
getResData获取接口返回数据Functionres => res-
validateStatus校验接口是否为成功Functioncode => code === 0-
cancelDuplicated是否取消重复请求Booleantrue-
duplicatedKeyFn如果开启了取消重复请求,如何生成重复标识Functionconfig => ${config.method}${config.url}-

单个api配置参数 优先级高于实例化参数

属性说明类型默认值备注

|disableHooks|是否禁用beforeHook、afterHook|Boolean|Object| - |-| |disableHandler|是否禁用错误处理函数|Boolean| false |-| |disableQs|是否在post请求的时候参数不进行Qs转换|Boolean| false |-| |beforeHook|接口发送之前处理函数,参数axios.config,优先级高于LcsAxios实例化参数 |Function|-|-| |afterHook|接口发送之前处理函数,参数response,优先级高于LcsAxios实例化参数 |Function|-|-| |duplicatedKey| 重复请求标识 |String|-|-|

示例

import Request from './request'
import config from '@/config'
import getHeader from './header'
import { getToken } from '@/utils/auth'
import Vue from 'vue'
const vm = new Vue()
const showToast = (txt) => {
  vm.$createToast({
    time: 2000,
    txt,
    type: 'error'
  }).show()
}
const platform = process.env.VUE_APP_INSURE_PLATFORM

const lcsAxiosConfig = {
  cancelDuplicated: false,
  netErrorTip: true,
  codeErrorTip: true,
  codeErrorTipFn: (msg) => {
    showToast(msg)
  },
  netErrorTipFn: (msg) => {
    showToast(msg)
  }
}
const axiosConfig = {
  baseURL: config.baseApi
}
export const http = new Request(
  {
    ...lcsAxiosConfig,
    beforeHook: (config) => {
      const headers = getHeader()
      config.params ? config.params.platform = platform : config.params = { platform }
      config.headers = Object.assign({}, config.headers, headers)
    }
  }, axiosConfig)
export const sitHttp = new Request(
  {
    ...lcsAxiosConfig,
    getResStatus: (res) => res.success ? 0 : -1,
    beforeHook: (config) => {
      const accessToken = getToken()
      const authorization = accessToken ? `Bearer ${accessToken}` : ''
      config.headers = Object.assign({}, config.headers, { accessToken, authorization })
    }
  },
  {
    baseURL: config.sitApi
  }
)

单个接口参数示例

// 获取用户信息
export async function getUserInfo (data) {
  const url = '/security/user/getUserInfo'
  return sitHttp.get(url, data, {
    disableTip: true
  })
}

export function loginByMobile ({ mobile, code }) {
  const url = '/security/social/token'
  const params = {
    grant_type: 'mobile',
    mobile,
    code
  }
  return sitHttp.fetch({
    url,
    params,
    method: 'post',
    config: {
      headers: {
        Authorization: `Basic ${process.env.VUE_APP_AUTH_BASIC}`,
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    }
  })
}