Skip to content

与服务端交互

框架使用 @pubinfo/openapi 来实现与服务端的交互。核心具有如下功能

  • 自动扫描生成请求文件,无需手动编写请求文件
  • 自动引入请求函数,无需手动引入。
  • 丰富的请求策略,支持分页、缓存、Token认证、无感刷新Token、上传策略、断点续传、请求重试等功能。

设置 baseURL

在根目录.env.* 文件里的 VITE_APP_API_BASEURL 这个参数就是配置请求的 baseURL

例如项目的真实接口请求地址为:

则可设置为 VITE_APP_API_BASEURL = http://api.test.com/

OpenAPI 配置

如果关闭了运行时自动生成接口文件,可以通过 pnpm run openapi 指令手动生成。

在应用目录下 apps/*/openapi.config.ts 文件里配置 openapi 的参数。

详细配置请查看 OpenAPI使用指南 文档。

注意

openapi 只在开发环境下启动,生产环境下不会生成接口文件。

扫描接口文档hash值和本地生成文件hash是否有区别,如果有区别则重新生成文件。如果需要强制重新生成文件,可以删除 src/api/modules 目录下的文件。

ts
import { defineConfig } from '@pubinfo/openapi'

export default defineConfig({
  imports: { '@/api': 'request' },
  batch: [
    {
      input: 'http://124.223.184.245:10003/pubinfo-sys/v3/api-docs/auth',
      output: './src/api/modules/auth',
    },
    {
      input: 'http://124.223.184.245:10003/pubinfo-sys/v3/api-docs/log',
      output: './src/api/modules/log',
    },
    {
      input: 'http://124.223.184.245:10003/pubinfo-sys/v3/api-docs/rbac',
      output: './src/api/modules/rbac',
    },
    {
      input: 'http://124.223.184.245:10003/pubinfo-sys/v3/api-docs/assist',
      output: './src/api/modules/assist',
    },
  ],
})

Request

@pubinfo/openapi 封装了一些通用方法 Typescript支持、响应缓存、无感数据交互、分页请求策略、Token认证拦截、无感刷新Token、通用的上传策略、自动拉取数据、断点续传策略、跨组件传值、自动拉取数据、请求重试等功能。

@pubinfo/openapi 生成的接口文件会通过 unplugin-auto-import 自动导入到 vite 项目中,不需要手动导入。

详细配置请查看 OpenAPI使用指南 文档。

拦截器

/src/api/index.ts 文件里实例化了 @pubinfo/openapi 对象,并对 requestresponse 设置了拦截器,拦截器的用处就是拦截每一次的请求和响应,然后做一些全局的处理。例如接口响应报错,可以在拦截器里用统一的报错提示来展示,方便业务开发。但因为每个公司和部门提供的接口标准不同,所以该文件拦截器部分的代码,需要开发者根据实际情况去修改调整。

代码很简单,首先初始化请求对象,然后 beforeRequestresponded 就分别是请求和响应的拦截代码了。

配套的权限管理系统做了双 token 的处理,tokenrefreshTokentoken 用于请求接口,refreshToken 用于刷新 tokentoken 过期后,会自动刷新 token,然后重新请求接口。

不同的响应code编码,统一放置在 src/api/enum/code.ts 文件里,方便统一管理。

ts
export enum RESPONSE_CODE {
  /**
   * @description
   * 接口请求成功
   */
  SUCCESS = 0,

  /**
   * @description
   * 运行异常
   */
  ERROR = -1,

  /**
   * @description
   * 操作失败,业务异常
   */
  BUSINESS_ERROR = 4,

  /**
   * @description
   * 账户锁定,请联系管理员
   */
  ACCOUNT_LOCKED = 400001001,

  /**
   * @description
   * 登录名或密码不正确
   */
  LOGINNAME_PASSWORD_WRONG = 400001002,

  /**
   * @description
   * 账户未启用,请联系管理员
   */
  ACCOUT_NOT_ENABLE = 400001003,

  /**
   * @description
   * token已过期
   */
  ACCESS_TOKEN_INVALID = 400001006,
  /**
   * @description
   * 刷新refreshToken已过期
   */
  LOGIN_TOKEN_INVALID = 400001004,

  /**
   * @description
   * 访问未授权
   */
  UNAUTHORIZED_ACCESS = 400001007,

  /**
   * @description
   * 验证码失效
   */
  CODE_OVERTIME = 400002001,

  /**
   * @description
   * 验证码不匹配
   */
  CODE_WRONG = 400002002,

  /**
   * @description
   * 首次登录,请修改初始密码
   */
  CHANGE_INIT_PASSWORD = 400003001,

  /**
   * @description
   * 登录密码已过期,请修改密码
   */
  PASSWORD_EXPIRED = 400003002,
}

跨域处理

生产环境的跨域需要服务端去解决,开发环境的跨域问题可在本地设置代理解决。如果本地开发环境请求接口提示跨域,可以设置 .env.development 文件里 VITE_OPEN_PROXY = true 开启代理。

ts
api.get('news/list') // http://localhost:9000/proxy/news/list
api.post('news/add') // http://localhost:9000/proxy/news/add

开启代理后,原有请求都会被指向到本地 http://localhost:5173/proxy ,因为 /proxy 匹配到了 vite.config.ts 里代理部分的设置,所以实际是请求依旧是 VITE_APP_API_BASEURL 所设置的地址。

javascript
export default {
  server: {
    // vite.config.ts 中 proxy 配置,该配置即用于代理 API 请求
    proxy: {
      '/proxy': {
        target: loadEnv(mode, process.cwd()).VITE_APP_API_BASEURL,
        changeOrigin: command === 'serve' && loadEnv(mode, process.cwd()).VITE_OPEN_PROXY === 'true',
        rewrite: path => path.replace(/\/proxy/, ''),
      },
    },
  }
}

Mock

Mock 数据是前端开发过程中必不可少的一环,是分离前后端开发的关键链路。通过预先跟服务器端约定好的接口,模拟请求数据甚至逻辑,能够让前端开发独立自主,不会被服务端的开发所阻塞。

提示

系统使用 vite-plugin-fake-server 提供开发和生产模拟服务。

Mock 数据编写规则请阅读 Mockjs 官方文档。

开发环境 mock

mock 文件存放在 /src/mock/ 下,建议按照不同模块区分文件夹。文件新增或修改后会自动更新,不需要手动重启,可以在代码控制台查看日志信息。

以下为示例代码:

ts
import { defineFakeRoute } from 'vite-plugin-fake-server/client'
import Mock from 'mockjs'

export default defineFakeRoute([
  {
    url: '/mock/news/list',
    method: 'get',
    response: () => {
      return {
        error: '',
        code: 0,
        data: Mock.mock({
          'list|5-10': [
            {
              title: '@ctitle',
            },
          ],
        }),
      }
    },
  },
])

为了让 mock 接口与真实接口共存,即项目开发中,部分请求 mock 接口,部分请求真实接口。需要在配置 mock 接口的时候,给 url 参数统一设置 /mock/ 前缀,并在调用接口的时候,使用 baseURL 强制修改此次请求的地址。

如下所示,其中 app/menu/list 会请求本地的 mock 接口,而 app/route/list 依旧请求真实接口,即使开启跨域代理也不影响。

ts
import request from '@/api'

/**
 * @description 后端获取路由数据
 */
export function GetApiRouteList(options?: { [key: string]: any }) {
  return request.Get<API.RouteList>('app/route/list', {
    ...(options || {}),
  })
}

/**
 * @description 后端获取路由数据
 */
export function GetApiMenuList(options?: { [key: string]: any }) {
  return request.Get<API.MenuList>('app/menu/list', {
    baseURL: '/mock',
    ...(options || {}),
  })
}

生产环境 mock

注意

生产环境一般都是调用真实接口,如果需要使用 mock 也只适用于一些简单的示例网站及预览网站。

需要注意一点,如果项目中有涉及到上传功能,请彻底关闭线上环境 mock ,在环境配置里设置 VITE_BUILD_MOCK = false ,不然线上环境将会报错。

默认已经配置好生产环境 mock ,如果不想让生产环境里的请求走 mock ,可在接口调用处删除 baseURL 设置,或直接删除 mock 接口文件。

开发环境与生产环境使用 mock 差异不大,比较大的区别是生产环境里调用 mock 接口,在控制台内看不到接口请求日志。

多服务

在后端是微服务下,basicURL 会有多个,可以在 openapi.config.ts 文件里配置多个 batch ,每个 batch 对应一个服务。

示例说明

下面是一个示例,有两个服务,一个是 pubinfo-auth 服务,一个是 pubinfo-sys 服务。 pubinfo-sys 提供 rbacassistconfigDatalog 四个模块的接口。 pubinfo-auth 提供 auth 模块的接口。

设置ENV 环境变量

设置 envenv.development 文件里的 VITE_APP_API_BASEURLVITE_APP_API_BASEURL_AUTH

VITE_APP_API_BASEURLpubinfo-sys 服务地址,VITE_APP_API_BASEURL_AUTHpubinfo-auth 服务地址。

env
# 接口请求地址,会设置到 axios 的 baseURL 参数上
VITE_APP_API_BASEURL = http://124.223.184.245:20010/api/pubinfo-sys
VITE_APP_API_BASEURL_AUTH = http://124.223.184.245:20010/api/pubinfo-auth

创建请求实例

api/request/index.ts 文件里,可以通过 import.meta.env 来获取环境变量,并生成请求实例

ts
import { createRequest } from '@/api/factory'

const basic = createRequest(import.meta.env.VITE_APP_API_BASEURL)
const auth = createRequest(import.meta.env.VITE_APP_API_BASEURL_AUTH)

export {
  basic,
  auth,
}

配置 openapi.config.ts

ts
import { presetName } from '@pubinfo/preset-openapi'
import { defineConfig } from '@pubinfo/openapi'

export default defineConfig({
  enabled: false,

  presets: [
    presetName({
      functionName: 'camelCase',
    }),
  ],

  imports: { '@/api/request': [{ name: 'basic', as: 'request' }] },
  batch: [
    {
      input: 'http://124.223.184.245:20010/api/pubinfo-auth/v3/api-docs/auth',
      output: './src/api/modules/auth',
      imports: { '@/api/request': [{ name: 'auth', as: 'request' }] },
    },
    {
      input: 'http://124.223.184.245:20010/api/pubinfo-sys/v3/api-docs/rbac',
      output: './src/api/modules/rbac',
    },
    {
      input: 'http://124.223.184.245:20010/api/pubinfo-sys/v3/api-docs/assist',
      output: './src/api/modules/assist',
    },
    {
      input: 'http://124.223.184.245:20010/api/pubinfo-sys/v3/api-docs/configData',
      output: './src/api/modules/configData',
    },
    {
      input: 'http://124.223.184.245:20010/api/pubinfo-sys/v3/api-docs/log',
      output: './src/api/modules/log',
    },
  ],

  hooks: {
    customType(schema, namespace, defaultFn) {
      // `int64` 在前端会精度丢失,可在此处调整对应字段的 `TS类型`
      if (schema?.type === 'integer' && schema?.format === 'int64')
        return 'number'

      return defaultFn(schema, namespace)
    },
  },
})

生成接口文件

执行 pnpm run openapi 生成接口文件,然后就可以在项目中使用了。

代理

配置代理需要使用统一前缀VITE_APP_API_

VITE_APP_API_ 为开头的请求basicUrl 会在开启VITE_OPEN_PROXY后自动代理到对应的服务上。

例如:

VITE_APP_API_BASEURL = http://124.223.184.245:20010/api/pubinfo-sys
VITE_APP_API_BASEURL_AUTH = http://124.223.184.245:20010/api/pubinfo-auth