跳到主要内容
版本:Next

RESTful API 集成

目录​

  1. 简介
  2. 项目结构概览
  3. 核心请求封装模块
  4. API 接口组织架构
  5. 认证与安全机制
  6. 环境配置与代理
  7. 错误处理与统一响应
  8. 缓存策略与性能优化
  9. 分页与参数处理
  10. Mock 数据与开发调试
  11. 实际使用示例
  12. 最佳实践与扩展指南

简介​

lmes-web-base 项目采用基于 axios 的 RESTful API 集成方案,提供了完整的前后端通信解决方案。该系统通过精心设计的请求封装层、统一的错误处理机制、智能的缓存策略以及灵活的环境配置,为前端应用提供了稳定可靠的 API 通信能力。

项目结构概览​

图表来源

核心请求封装模块​

request.ts 模块架构​

request.ts 是整个 API 集成的核心模块,基于 axios 进行了深度封装,提供了完整的请求生命周期管理。

图表来源

请求拦截器功能​

请求拦截器负责在请求发送前进行预处理:

  1. 认证令牌注入:自动从 Session 存储中获取 Token 并添加到 Authorization 头
  2. 默认请求头设置:合并默认的 Content-Type 和其他业务相关头部
  3. XML 字符串处理:识别并正确处理 XML 格式的字符串数据
  4. 静默模式支持:根据配置决定是否显示加载动画

响应拦截器功能​

响应拦截器处理服务器返回的数据:

  1. 数据提取:自动提取 response.data 部分
  2. 错误代理检测:识别并处理代理未找到的接口
  3. Blob 类型处理:特殊处理文件下载场景
  4. 状态码映射:将 HTTP 状态码映射为用户友好的错误消息

章节来源

API 接口组织架构​

项目级 API 组织​

项目采用模块化的 API 组织方式,每个业务领域都有独立的 API 文件:

图表来源

API 方法类型支持​

系统支持完整的 RESTful 方法:

  • GET:用于数据查询和资源获取
  • POST:用于数据创建和复杂查询
  • PUT:用于资源更新
  • DELETE:用于资源删除

章节来源

认证与安全机制​

Token 注入机制​

系统实现了自动化的 Token 管理机制:

// 自动从 Session 存储获取 Token
const token = Session.get('Token')

// 动态计算 Authorization 头
get Authorization() {
return token ? `Bearer ${token}` : undefined
}

请求头安全策略​

  1. Content-Type 强制:确保所有请求都使用 application/json 格式
  2. 项目标识:自动注入 X-Project 头部标识当前项目
  3. 客户端标识:添加 X-Client-Id 支持多客户端识别
  4. 语言环境:动态设置 Accept-Language 头部

重新登录机制​

当遇到 401 或 403 状态码时,系统会触发重新登录弹窗:

图表来源

章节来源

环境配置与代理​

环境变量驱动的 baseURL 切换​

系统支持通过多种方式配置 baseURL:

// 优先从 URL 参数获取
let baseURL = params.get('baseURL') || ''

// 支持通过 baseURL 参数覆盖
console.info('[baseURL]', baseURL)

开发环境代理配置​

开发环境通过 Vite 配置了完整的代理系统:

图表来源

路径别名配置​

系统配置了多个路径别名以简化导入:

  • @ → ./src
  • components → ./src/components
  • sdk → ./src/cms/sdk.es.js

章节来源

错误处理与统一响应​

统一错误处理机制​

系统实现了多层次的错误处理:

图表来源

错误消息处理​

系统支持多种错误消息来源:

  1. 响应体错误:优先从 data.msg、data.message 等字段获取
  2. 状态文本:使用 statusText 作为备选
  3. 默认消息:使用 "请求出错" 作为最终备选

加载动画管理​

系统实现了智能的加载动画管理:

// 请求计数器
let reqNum: number = 0

// 显示加载动画
const setLoading = (silent: boolean) => {
if (silent) return

reqNum++
if (reqNum === 1) {
loadingInstance = ElLoading.service(loadingOptions)
}
}

// 关闭加载动画
const closeLoading = (silent: boolean) => {
if (silent) return
reqNum--
if (reqNum <= 0) {
reqNum = 0
loadingInstance && loadingInstance.close()
}
}

章节来源

缓存策略与性能优化​

内存缓存机制​

系统实现了基于内存的缓存策略:

图表来源

变量查询缓存​

系统对变量查询实现了 5 分钟缓存机制:

private async queryVariable(next: () => void) {
const size = this.getState(Base.MAP_KEY)?.size
const t = this.getState(Base.CACHE_KEY) || Date.now()

// 缓存有效期内直接返回
if (size > 0 && Date.now() - t < Base.CACHE_TIME) {
return next && next()
}

// 缓存过期,发起新请求
try {
const vars = await request.get('/api/v1/variable/query')
const varMap = this.transformArrayToMap(vars.result)
this.setState(Base.CACHE_KEY, Date.now())
this.setState(Base.MAP_KEY, varMap)
next && next()
} catch (error) {
console.error(error, '变量查询接口报错,暂停请求')
}
}

节流防抖机制​

系统提供了高性能的节流防抖工具:

export const genSetInterval = (fn: () => void, time: number = 33): Timer => {
let timerId: number | null = null
let lastTime = performance.now()

const loop = (currentTime: number) => {
const deltaTime = currentTime - lastTime

if (deltaTime >= time) {
fn()
lastTime = currentTime - (deltaTime % time) // 保留余下的时间,减少漂移
}

timerId = requestAnimationFrame(loop)
}

return {
start() {
if (timerId === null) {
lastTime = performance.now()
timerId = requestAnimationFrame(loop)
}
},
clear() {
if (timerId !== null) {
cancelAnimationFrame(timerId)
timerId = null
}
},
}
}

章节来源

分页与参数处理​

分页参数标准化​

系统实现了统一的分页参数处理机制:

图表来源

分页组件实现​

系统提供了两个分页组件:

  1. BaseTable 分页:集成在表格组件中
  2. MyPages 组件:独立的分页控件
// 分页参数获取
const getPaginationParams = () => {
return {
pageNum: pageNum.value,
pageSize: params.value.MaxResultCount,
totalCount: totalCount.value,
}
}

// 表格滚动到指定行
const scrollToRow = async ({ row, skip }: any) => {
if (skip) {
if (totalCount.value > dataSource.value.length) {
// 跳转到最后一页面
pageNum.value = Math.ceil(totalCount.value / params.value.MaxResultCount)
params.value.SkipCount = (pageNum.value - 1) * params.value.MaxResultCount
}
await getTableList()
skipRow(dataSource.value[dataSource.value.length - 1])
} else {
skipRow(row)
}
}

参数序列化处理​

系统自动处理各种类型的参数序列化:

// 自动 JSON 序列化
if (
typeof config.data !== 'object' &&
!isXMLString &&
config.headers['Content-Type'].match(/application\/json/i)
) {
config.data = JSON.stringify(config.data)
}

章节来源

Mock 数据与开发调试​

Mock 系统架构​

系统提供了完整的 Mock 数据支持:

图表来源

开发环境调试支持​

系统支持多种开发调试模式:

  1. 静态文件 Mock:通过 mock.json 提供静态数据
  2. 动态 Mock:通过 index.js 提供动态行为
  3. 多语言 Mock:支持本地化测试
  4. 组件 Mock:支持组件级别的模拟

接口联调机制​

开发环境提供了完整的接口联调支持:

// 开发环境与生产环境的 API 路由切换
return import.meta.env.PROD
? sdk.request({ url, method, params: { ...provider } })
: request({ url, method, params: { ...provider } })

章节来源

实际使用示例​

基础 API 调用​

// 项目配置获取
export const getProjectConfig = (name: string) => {
return request.get(`/projectApi/env?name=${name}`)
}

// 组件创建
export const createWidget = (data) => {
return request.post(`/projectApi/create`, data)
}

高级 API 调用​

// 产品列表查询(带条件过滤)
function getproductList(data: any, hasFormula: boolean = true) {
const url = `api/v1/messuite/query/product?filter=${data.filter}&hasFormula=${hasFormula}`
const method = 'get'
return request({ url, method })
}

// 工序列表查询(带能力类型过滤)
function getWorksectionList(data: any) {
const url = `api/v1/messuite/query/worksection?filter=${data.filter}&abilityType=${data.abilityType}&includeDetails=${data.includeDetails}`
const method = 'get'
return request({ url, method })
}

错误处理示例​

// 带静默模式的请求
try {
const result = await request.get('/api/v1/data', {
silent: true, // 不显示加载动画
unLogError: true, // 不显示错误提示
})
} catch (error) {
console.error('API 调用失败:', error)
}

文件上传示例​

// 文件上传(支持 FormData)
export const postImport = (file: FormData) => {
return request({
url: `/api/v1/zc/productsop/uploadsop`,
method: 'post',
contentType: 'multipart/form-data',
headers: { accept: '*/*' },
data: file,
})
}

章节来源

最佳实践与扩展指南​

扩展自定义请求头​

// 在请求配置中添加自定义头部
const customRequest = async (url: string, data?: any) => {
return request({
url,
method: 'post',
headers: {
'X-Custom-Header': 'custom-value',
'X-Additional-Info': 'additional-info',
},
data,
})
}

适配分页参数格式​

// 统一分页参数处理
const getPagedParams = (pageNum: number, pageSize: number) => {
return {
SkipCount: (pageNum - 1) * pageSize,
MaxResultCount: pageSize,
}
}

// 使用示例
const fetchData = async (pageNum: number, pageSize: number) => {
const params = getPagedParams(pageNum, pageSize)
return request.get('/api/v1/data/list', { params })
}

接口版本控制​

// 版本化 API 调用
const apiVersion = 'v1'

const getVersionedRequest = (endpoint: string) => {
return request.get(`/api/${apiVersion}/${endpoint}`)
}

// 使用示例
const getData = async () => {
return getVersionedRequest('data')
}

高频请求节流​

// 节流包装器
const createThrottledRequest = (fn: Function, delay: number = 300) => {
let lastCall = 0
return async (...args: any[]) => {
const now = Date.now()
if (now - lastCall < delay) {
return Promise.reject(new Error('请求过于频繁'))
}
lastCall = now
return fn(...args)
}
}

// 使用示例
const throttledGetData = createThrottledRequest(getData)

扩展错误处理​

// 自定义错误处理器
const handleError = (error: any) => {
switch (error.status) {
case 400:
ElMessage.error('请求参数错误')
break
case 401:
ElMessage.error('请先登录')
break
case 403:
ElMessage.error('权限不足')
break
case 404:
ElMessage.error('资源不存在')
break
default:
ElMessage.error('网络错误,请稍后重试')
}
}

性能监控集成​

// 请求性能监控
const monitoredRequest = async (config: any) => {
const startTime = performance.now()
try {
const result = await request(config)
const endTime = performance.now()
console.log(`API ${config.url} 耗时: ${endTime - startTime}ms`)
return result
} catch (error) {
const endTime = performance.now()
console.error(`API ${config.url} 失败,耗时: ${endTime - startTime}ms`)
throw error
}
}

这个文档全面涵盖了 lmes-web-base 项目中 RESTful API 集成的所有关键方面,从基础的请求封装到高级的性能优化,为开发者提供了完整的技术参考和最佳实践指导。通过合理的架构设计和丰富的功能特性,该系统能够满足现代 Web 应用对 API 集成的各种需求。