Skip to content

http

基于axios封装。

使用示例

ts
import { http } from '@fs/lib'

function fetchDetail() {
  http.get('https://test-wms-api.whgxwl.com/wms/base/warehouse/getById/1').then((res) => {
    // {
    //   code: 200,
    //   msg: '成功',
    //   traceId: 'Ps1lkfudU4uAlCzv',
    //   data: { id: 1, code: 'WH', createdAt: '2023-12-23T15:36:40', updatedAt: '2024-11-18T20:57:01' }
    // }
    console.log(res)
  })
}
fetchDetail()

说明,

http 模块来源于wms首次提交梳理(少许必要的改动)。即fs-cli脚手架创建的模板项目,gitlab地址:https://gitlab.fs.com:31549/SystemRDCenter/basic/fs-cli-project-template/-/tree/main/vue3-admin-template

所以API跟历史项目是一致的,至少跟vue3-admin-template中的http是完全兼容的。

TIP

API细节详见vue3-admin-template模板中代码

有少许几处变更:

  • 针对http.get,http.post第一个参数的处理

WARNING

二次封装第三方模块时,尽量与官方API保持一致,以减少不必要的心智负担,如官方axios针对get,post等别名第一个参数皆为stringvue3-admin-template中第一个参数都为object,与官方API不一致。

为保持与官方API一致,此处有修改,同时针对object也会向后兼容。

  • 针对http模块抽离业务拦截器服务

目前梳理来看,各业务系统针对axios拦截处理基本100%一致,故抽离为http-interceptor服务,方便各业务系统复用。

即http模块内置统一的业务拦截器,即便如此,也无法避免未来一些业务系统可能出现不一样的拦截处理,此时可自行注册拦截器,如dcs中的差异处理:

ts
class InterceptorService extends BaseInterceptorService {
  request(config: HttpInternalAxiosRequestConfig): HttpInternalAxiosRequestConfig {
    const user = userStorage.get()
    if (user) {
      config.headers['Admin-Id'] = user?.adminId
      // config.headers['Admin-Name'] = user?.userName
    }
    return config
  }
}
const interceptorService = new InterceptorService()

const httpIns = http.getInstance()
httpIns.defaults.baseURL = import.meta.env.VITE_GLOB_API_URL
httpIns.interceptors.request.use(interceptorService.request)

简单来说就是内置的都是通用的,一致的解决方案,但是要留好不一致的口子,方便后续业务系统自行定制。

业务场景说明

  • 基本业务

因为后端的Request,Response基本一致,所以内置通用拦截器,主要是携带通用请求头以及针对响应统一处理。

ts
import { http } from '@fs/lib'

const fetchDetail = (id: string) => http.get(`/wms/base/warehouse/getById/${id}`)

fetchDetail('1').then((res) => {
  // {
  //   code: 200,
  //   msg: '成功',
  //   traceId: 'Ps1lkfudU4uAlCzv',
  //   data: { id: 1, code: 'WH', createdAt: '2023-12-23T15:36:40', updatedAt: '2024-11-18T20:57:01' }
  // }
  console.log(res)
})

由于上述响应会携带业务code,msg,实际开发时还需要大量的code === 200做判断,这是很不合理的,明显拦截器中处理更为合适。

如搜索其他业务系统如下

resCode

TIP

由于上述历史原因,并考虑向后兼容(假如上述项目采用大仓的依赖收敛方案,可以做到无侵入升级),大仓中的http模块内置的拦截器仍保持现状,业务处理只是加了个helper辅助处理。

业务中可采用如下方案,或者interceptors处理。

ts
import { http, withHadlerResponse } from '@fs/lib'

const fetchDetail = withHadlerResponse((id: string) =>
  http.get({
    url: `/wms/base/warehouse/getById/${id}`,
  }),
)

fetchDetail('1').then((res) => {
  // { id: 1, code: 'WH', createdAt: '2023-12-23T15:36:40', updatedAt: '2024-11-18T20:57:01' }
  console.log(res)
})

同理还有一个withHadlerExportFile用于处理文件流下载。

ts
import { http, withHadlerExportFile } from '@fs/lib'

const downloadExcel = withHadlerExportFile((data: { id: number }) =>
  http.post({
    url: '/wms/product/general/warehouse/inventoryHandleDownload',
    responseType: 'blob',
    data,
  }),
)

downloadExcel({ id: 1 }, { filename: '模板.xlsx' })
  • 文件导出
ts
import { http, withHadlerExportFile } from '@fs/lib'

// api.ts
export const exportExcel = withHadlerExportFile((params: any) => {
  return http.get({
    url: '/wms/base/interface/log/export',
    params,
    responseType: 'blob',
  })
})

function handleExport() {
  api.exportExcel({ statusCode: 'ERROR' }, { filename: '接口监控管理列表.xlsx' }).then(() => {
    console.log('success')
  })
}

导出文件名取自header时,自行处理header,提供downloadByStream辅助函数,

ts
import { downloadByStream, http, withHadlerResponse } from '@fs/lib'

// api.ts
export async function exportExcel(params: any) {
  const res = await http.get<any>({
    url: '/wms/base/interface/log/export',
    params,
    responseType: 'blob',
    isReturnNativeResponse: true, // +++注意此处
  })
  // content-disposition: attachment; filename="20250519173023_base_interface_log.xlsx"
  const [, filename] = res.headers['content-disposition'].split('filename=')
  return await downloadByStream(res.data, { filename: filename.replace(/"/g, '') })
}

function handleExport() {
  api.exportExcel({ statusCode: 'ERROR' }).then(() => {
    console.log('success')
  })
}
  • 全新的instance

假如业务中的请求,不与现有拦截器一致(如业务中的s3接口),可自行创建新的instance,与axios完全一致。

ts
import { http } from '@fs/lib'

const instance = http.create({
  baseURL: 'https://some-domain.com/api/',
  timeout: 1000,
  headers: { 'X-Custom-Header': 'foobar' },
})

相关API参见axios文档。

API

ts
export interface HttpRequestConfig extends AxiosRequestConfig {
  /**
   * 是否忽略重复请求,默认 true
   */
  ignoreCancelToken?: boolean
  /**
   * 是否显示错误信息,默认 true
   */
  errorMessageShow?: boolean
  /**
   * 是否返回原生响应头,比如:需要获取响应头时使用该属性,默认 false
   */
  isReturnNativeResponse?: boolean
}