uni-app 还在手写请求?alova 帮你全搞定!

在上一篇《uni-app 网络请求终极选型》中,我们对比了四大主流请求方案。本文将深入讲解如何在 uni-app 项目中完整接入 alova,按照"安装 → 配置 → 使用"的步骤,让你的请求体验飞起来!

为什么选择 alova?

alova 不仅仅是一个请求库,更是一个完整的请求策略解决方案:

  • 声明式 API:把 URL、参数、缓存策略封装进 Method 实例,一行 Hook 拿到响应式 loading / data / error,告别 try-catch
  • 策略化:内置分页、防抖、轮询、断点续传等 20+ 场景 Hook,开箱即用
  • 高性能:并发请求自动合并,多级缓存可离线,断网先读缓存再补发
  • 类型友好:Method 与 Hook 自带完整 TS 推导
  • 体积小巧:核心 4 KB,零依赖,Tree-shaking 只打包用到的代码

项目环境准备

本教程基于 WotDemo github.com/wot-ui/wot-... 项目,这是一个现代化的 uni-app 开发模板,包含:

  • Vite + TypeScript 构建
  • Vue 3 + Composition API
  • UnoCSS 原子化CSS
  • Pinia 状态管理
  • ESLint + Prettier 代码规范

第一步:安装依赖

1.1 安装核心包

bash 复制代码
# 推荐使用 pnpm
pnpm add alova @alova/adapter-uniapp

# 或使用 npm
npm install alova @alova/adapter-uniapp

# 或使用 yarn
yarn add alova @alova/adapter-uniapp

1.2 安装代码生成工具(推荐)

为了提升开发效率,强烈推荐安装 @alova/wormhole 代码生成工具:

bash 复制代码
# 安装代码生成工具(开发依赖)
pnpm add -D @alova/wormhole

# 安装 Mock 数据支持(可选)
pnpm add @alova/mock

1.3 验证安装

安装完成后,检查 package.json 确认依赖已正确添加:

json 复制代码
{
  "dependencies": {
    "alova": "^3.3.4",
    "@alova/adapter-uniapp": "^2.0.14",
    "@alova/mock": "^2.0.17"
  },
  "devDependencies": {
    "@alova/wormhole": "^1.1.2"
  }
}

第二步:环境配置

2.1 环境变量配置

在项目根目录创建环境变量文件:

.env.development

bash 复制代码
# 开发环境配置
VITE_API_BASE_URL=http://localhost:3000/api
VITE_ENV_NAME=development

.env.production

bash 复制代码
# 生产环境配置
VITE_API_BASE_URL=https://api.yourapp.com
VITE_ENV_NAME=production

.env.test

bash 复制代码
# 测试环境配置
VITE_API_BASE_URL=https://test-api.yourapp.com
VITE_ENV_NAME=test

2.2 TypeScript 类型声明

src/types/env.d.ts 中添加环境变量类型声明:

typescript 复制代码
/// <reference types="vite/client" />

interface ImportMetaEnv {
  readonly VITE_API_BASE_URL: string
  readonly VITE_ENV_NAME: string
  // 更多环境变量...
}

interface ImportMeta {
  readonly env: ImportMetaEnv
}

2.3 在 alova 实例中使用环境变量

参考项目中的实际配置,在 src/api/core/instance.ts 中使用环境变量:

typescript 复制代码
export const alovaInstance = createAlova({
  // 使用环境变量配置 API 基础地址,提供默认值作为兜底
  baseURL: import.meta.env.VITE_API_BASE_URL || 'https://petstore3.swagger.io/api/v3',

  // 开发环境下的调试日志
  beforeRequest: (method) => {
    // 开发环境下记录请求日志和环境信息
    if (import.meta.env.MODE === 'development') {
      console.log(`[Alova Request] ${method.type} ${method.url}`, method.data || method.config.params)
      console.log(`[API Base URL] ${import.meta.env.VITE_API_BASE_URL}`)
      console.log(`[Environment] ${import.meta.env.VITE_ENV_NAME}`)
    }
  }
})

2.4 环境切换优势

通过环境变量配置,你可以:

  • 开发环境:连接本地开发服务器,启用详细日志
  • 测试环境:连接测试服务器进行集成测试
  • 生产环境:连接正式的生产服务器,关闭调试日志
  • 灵活切换:通过修改环境变量文件快速切换不同环境

第三步:配置代码生成工具

3.1 创建 alova.config.ts 配置文件

在项目根目录创建 alova.config.ts 配置文件:

typescript 复制代码
import type { Config } from '@alova/wormhole'

export default <Config>{
  generator: [
    {
      // OpenAPI 文档地址(支持本地文件或在线地址)
      input: 'https://petstore3.swagger.io/api/v3/openapi.json',

      // 文档平台类型
      platform: 'swagger',

      // 生成代码的输出目录
      output: 'src/api',

      // 响应数据的媒体类型
      responseMediaType: 'application/json',

      // 请求体数据的媒体类型
      bodyMediaType: 'application/json',

      // 生成的 API 版本
      version: 3,

      // 生成代码类型
      type: 'typescript',

      // 全局 API 名称
      global: 'Apis',

      // API 处理函数
      handleApi: (apiDescriptor) => {
        // 过滤掉已废弃的 API
        if (apiDescriptor.deprecated) {
          return undefined
        }
        return apiDescriptor
      },
    },
  ],

  // 自动更新配置
  autoUpdate: {
    // 编辑器启动时更新
    launchEditor: true,
    // 每5分钟检查更新
    interval: 5 * 60 * 1000,
  },
}

2.2 添加生成命令

package.json 中添加代码生成命令:

json 复制代码
{
  "scripts": {
    "alova-gen": "alova gen -f"
  }
}

2.3 生成 API 代码

运行命令生成 API 接口代码:

bash 复制代码
# 生成 API 代码
pnpm run alova-gen

# 或直接使用
pnpm run alova gen -f

2.4 生成后的目录结构

python 复制代码
src/
├── api/
│   ├── apiDefinitions.ts    # 自动生成的 API 定义
│   ├── createApis.ts        # 自动生成的 API 创建函数
│   ├── globals.d.ts         # 自动生成的全局类型定义
│   ├── index.ts             # 统一导出文件
│   ├── core/                # 核心配置目录
│   │   └── instance.ts      # alova 实例配置
│   └── mock/                # Mock 数据目录(可选)

2.5 配置 alova 实例

src/api/core/instance.ts 中创建 alova 实例,参考项目实际配置:

typescript 复制代码
import { createAlova } from 'alova'
import vueHook from 'alova/vue'
import AdapterUniapp from '@alova/adapter-uniapp'
import mockAdapter from '../mock/mockAdapter'
import { handleAlovaError, handleAlovaResponse } from './handlers'

export const alovaInstance = createAlova({
  // 基础URL - 支持环境变量配置
  baseURL: import.meta.env.VITE_API_BASE_URL || 'https://petstore3.swagger.io/api/v3',

  // 使用 uni-app 适配器,支持 Mock 数据
  ...AdapterUniapp({
    mockRequest: mockAdapter,
  }),

  // Vue 3 状态钩子
  statesHook: vueHook,

  // 全局请求拦截器
  beforeRequest: (method) => {
    // 为 POST/PUT/PATCH 请求添加 Content-Type
    if (['POST', 'PUT', 'PATCH'].includes(method.type)) {
      method.config.headers['Content-Type'] = 'application/json'
    }

    // 为 GET 请求添加时间戳防止缓存
    if (method.type === 'GET' && CommonUtil.isObj(method.config.params)) {
      method.config.params._t = Date.now()
    }

    // 开发环境下记录请求日志
    if (import.meta.env.MODE === 'development') {
      console.log(`[Alova Request] ${method.type} ${method.url}`, method.data || method.config.params)
      console.log(`[API Base URL] ${import.meta.env.VITE_API_BASE_URL}`)
      console.log(`[Environment] ${import.meta.env.VITE_ENV_NAME}`)
    }
  },

  // 全局响应拦截器
  responded: {
    // 成功处理器 - 在 handlers.ts 中定义
    onSuccess: handleAlovaResponse,

    // 错误处理器 - 在 handlers.ts 中定义
    onError: handleAlovaError,

    // 完成处理器 - 成功或失败后都会执行
    onComplete: async () => {
      // 可以在这里进行清理或日志记录
    },
  },

  // 请求超时时间(60秒)
  timeout: 60000,

  // 全局关闭缓存(设置为 null)
  cacheFor: null,
})

export default alovaInstance

响应和错误处理器

src/api/core/handlers.ts 中定义统一的响应和错误处理逻辑:

typescript 复制代码
import type { Method } from 'alova'
import router from '@/router'

// 自定义 API 错误类
export class ApiError extends Error {
  code: number
  data?: any

  constructor(message: string, code: number, data?: any) {
    super(message)
    this.name = 'ApiError'
    this.code = code
    this.data = data
  }
}

// API 响应结构类型
interface ApiResponse {
  code: number
  msg?: string
  data?: any
  success?: boolean
  total?: number
  more?: boolean
}

// 处理成功响应
export async function handleAlovaResponse(response: UniApp.RequestSuccessCallbackResult) {
  const globalToast = useGlobalToast()
  const { statusCode, data } = response

  // 处理 401/403 未授权错误
  if (statusCode === 401 || statusCode === 403) {
    globalToast.error({ msg: '登录已过期,请重新登录!', duration: 500 })
    setTimeout(() => {
      router.replaceAll({ name: 'login' })
    }, 500)
    throw new ApiError('登录已过期,请重新登录!', statusCode, data)
  }

  // 处理 HTTP 错误状态码
  if (statusCode >= 400) {
    globalToast.error(`请求失败,状态码: ${statusCode}`)
    throw new ApiError(`请求失败,状态码: ${statusCode}`, statusCode, data)
  }

  // 开发环境下记录响应日志
  if (import.meta.env.MODE === 'development') {
    console.log('[Alova Response]', data)
  }

  return data as ApiResponse
}

// 处理请求错误
export function handleAlovaError(error: any, method: Method) {
  const globalToast = useGlobalToast()

  // 开发环境下记录错误日志
  if (import.meta.env.MODE === 'development') {
    console.error('[Alova Error]', error, method)
  }

  // 处理不同类型的错误
  if (error.name === 'NetworkError') {
    globalToast.error('网络错误,请检查您的网络连接')
  }
  else if (error.name === 'TimeoutError') {
    globalToast.error('请求超时,请重试')
  }
  else if (error instanceof ApiError) {
    globalToast.error(error.message || '请求失败')
  }
  else {
    globalToast.error('发生意外错误')
  }

  throw error
}

关键配置说明:

  1. 环境变量支持 :使用 import.meta.env.VITE_API_BASE_URL 支持不同环境配置
  2. Mock 数据集成 :通过 mockAdapter 支持开发阶段的数据模拟
  3. Vue 3 集成 :使用 vueHook 确保与 Vue 3 响应式系统的兼容
  4. 模块化处理 :将响应和错误处理逻辑分离到 handlers.ts 文件中
  5. 统一错误处理 :自定义 ApiError 类,统一处理各种错误场景
  6. 自动登录跳转:401/403 错误时自动跳转到登录页面
  7. 开发调试:在开发环境下自动记录请求和响应日志

第三步:在页面中使用

3.1 自动导入配置(开发体验优化)

WotDemo 项目通过 unplugin-auto-import 配置了自动导入,开发者无需手动引入 API 和 alova hooks。

vite.config.ts 中的配置:

typescript 复制代码
AutoImport({
  imports: [
    'vue',
    '@vueuse/core',
    'pinia',
    'uni-app',
    {
      from: 'alova/client',
      imports: ['usePagination', 'useRequest', 'useWatcher', 'useForm'],
    }
  ],
  // 自动导入 src/api 目录下的所有导出
  dirs: ['src/composables', 'src/store', 'src/utils', 'src/api'],
  dts: 'src/auto-imports.d.ts',
  vueTemplate: true,
})

这意味着你可以直接使用,无需手动导入:

typescript 复制代码
// ✅ 无需手动导入,直接使用
const { data, loading } = useRequest(Apis.pet.findPetsByStatus)

// ❌ 不再需要这样手动导入
// import { useRequest } from 'alova'
// import { Apis } from '@/api'

3.2 基础数据获取

参考项目中的 src/pages/request/index.vue

typescript 复制代码
// 🎉 直接使用,无需导入!
// useRequest 和 Apis 都已自动导入

// 获取宠物列表
const {
  data,
  loading,
  error,
  send: loadPetData
} = useRequest(
  (status: 'available' | 'pending' | 'sold' = 'available') => Apis.pet.findPetsByStatus({
    params: { status }
  }),
  {
    immediate: false,
    initialData: []
  }
)

// 用户登录演示
const {
  data: loginResult,
  loading: loginLoading,
  send: performLogin
} = useRequest(
  (username: string, password: string) => Apis.user.loginUser({
    params: { username, password }
  }),
  {
    immediate: false
  }
)

// 演示函数
function demoLoadPets() {
  loadPetData('available')
}

function demoLogin() {
  performLogin('testuser', 'testpass')
}

3.2 监听式请求

typescript 复制代码
import { ref } from 'vue'
import { useWatcher } from 'alova'
import { Apis } from '@/api'

// 响应式状态
const petStatus = ref<'available' | 'pending' | 'sold'>('available')

// 监听状态变化,自动发送请求
const {
  data: petList,
  loading: petLoading,
  error: petError
} = useWatcher(
  () => Apis.pet.findPetsByStatus({
    params: { status: petStatus.value }
  }),
  [petStatus],
  {
    immediate: true,
    debounce: 300
  }
)

// 切换状态
function changeStatus(status: 'available' | 'pending' | 'sold') {
  petStatus.value = status
}

3.3 分页请求

typescript 复制代码
import { usePagination } from 'alova'
import { Apis } from '@/api'

// 分页请求
const {
  data: inventoryList,
  loading: listLoading,
  page,
  pageSize,
  total,
  isLastPage,
  reload
} = usePagination(
  (page, pageSize) => Apis.store.getInventory(),
  {
    initialPage: 1,
    initialPageSize: 10,
    preloadPreviousPage: true,
    preloadNextPage: true,
    total: res => Object.keys(res).length,
    data: res => Object.entries(res).map(([key, value]) => ({ name: key, count: value }))
  }
)

// 加载更多
function loadMore() {
  if (!isLastPage.value && !listLoading.value) {
    page.value++
  }
}

3.4 表单提交

typescript 复制代码
import { reactive } from 'vue'
import { useForm } from 'alova'
import { Apis } from '@/api'

// 表单数据
const formData = reactive({
  name: '',
  status: 'available' as const,
  category: { id: 1, name: 'Dogs' },
  photoUrls: ['https://example.com/photo.jpg']
})

// 表单提交
const {
  loading: submitting,
  send: submitForm,
  onSuccess,
  onError
} = useForm(
  formData => Apis.pet.addPet({ data: formData }),
  {
    immediate: false,
    resetAfterSubmitting: true
  }
)

// 成功回调
onSuccess(() => {
  const globalToast = useGlobalToast()
  globalToast.success('添加成功')
})

// 错误回调
onError((error) => {
  const globalToast = useGlobalToast()
  globalToast.error(error.message || '添加失败')
})

// 提交表单
function handleSubmit() {
  if (!formData.name) {
    const globalToast = useGlobalToast()
    globalToast.warning('请输入宠物名称')
    return
  }
  submitForm(formData)
}


第四步:开发环境优化

4.1 使用 @alova/wormhole 的优势

使用代码生成工具的主要优势:

  • 自动同步:API 文档更新时自动重新生成代码
  • 类型安全:自动生成完整的 TypeScript 类型定义
  • 减少错误:避免手动编写 API 时的拼写错误
  • 提升效率:无需手动维护大量的 API 接口代码

4.2 Mock 数据支持

在开发阶段,可以使用 alova 的 Mock 功能:

typescript 复制代码
import { createAlovaMockAdapter } from '@alova/mock'

// Mock 适配器
const mockAdapter = createAlovaMockAdapter([
  {
    path: '/pet/{petId}',
    method: 'GET',
    response: ({ pathParams }) => ({
      id: pathParams.petId,
      name: 'Mock Pet',
      status: 'available',
      category: { id: 1, name: 'Dogs' },
      photoUrls: ['https://example.com/mock.jpg']
    })
  }
], {
  // 延迟响应
  delay: [300, 800],
  // Mock 开关
  enable: process.env.NODE_ENV === 'development'
})

// 在 alova 实例中使用
export default createAlova({
  baseURL: 'https://petstore3.swagger.io/api/v3',
  ...mockAdapter,
  // 其他配置...
})

4.3 环境配置

创建 src/api/core/config.ts 管理不同环境的配置:

typescript 复制代码
// 环境配置
const config = {
  development: {
    baseURL: 'https://petstore3.swagger.io/api/v3',
    timeout: 10000,
    enableMock: true
  },
  production: {
    baseURL: 'https://api.yourproject.com',
    timeout: 5000,
    enableMock: false
  }
}

export const apiConfig = config[process.env.NODE_ENV as keyof typeof config] || config.development

总结

通过本文的四个步骤,我们已经完整掌握了在 uni-app 中使用 alova 的全流程:

✅ 完成的配置

  1. 安装依赖 - 正确安装 alova 核心库和适配器
  2. 配置代码生成工具 - 使用 @alova/wormhole 自动生成 API 代码
  3. 页面使用 - 掌握四种常见请求场景
  4. 开发优化 - Mock 数据、环境配置
  5. 性能优化 - 缓存策略、预加载、错误处理

🚀 核心优势

  • 开发效率提升:智能缓存和请求去重减少重复请求
  • 用户体验优化:静默提交和预加载提升响应速度
  • 代码质量保证:TypeScript 支持和统一错误处理
  • 维护成本降低:模块化设计和最佳实践

📚 进阶学习

现在你可以在自己的 uni-app 项目中应用这些配置,打造高性能、用户体验优秀的跨端应用!wot demo 已接入 alova,你可以可以直接使用wot-demo进行体验。

相关文章

告别 HBuilderX,拥抱现代化!这个模板让 uni-app 开发体验起飞

uni-app 网络请求终极选型

Vue3 uni-app 主包 2 MB 危机?1 个插件 10 分钟瘦身

uni-app 也能像 Vue 一样用 App.vue 了?这款插件做到了!

有问题欢迎在评论区讨论,让我们一起打造更好的 uni-app 开发体验! 🚀

相关推荐
key_Go9 分钟前
18.WEB 服务器
服务器·前端·firefox
碎像33 分钟前
uni-app实战教程 从0到1开发 画图软件 (学会画图)
前端·javascript·css·程序人生·uni-app
Hilaku1 小时前
从“高级”到“资深”,我卡了两年和我的思考
前端·javascript·面试
WebInfra1 小时前
Rsdoctor 1.2 发布:打包产物体积一目了然
前端·javascript·github
用户52709648744902 小时前
SCSS模块系统详解:@import、@use、@forward 深度解析
前端
兮漫天2 小时前
bun + vite7 的结合,孕育的 Robot Admin 【靓仔出道】(十一)
前端·vue.js
xianxin_2 小时前
CSS Text(文本)
前端
秋天的一阵风2 小时前
😈 藏在对象里的 “无限套娃”?教你一眼识破循环引用诡计!
前端·javascript·面试
电商API大数据接口开发Cris2 小时前
API 接口接入与开发演示:教你搭建淘宝商品实时数据监控
前端·数据挖掘·api
用户1409508112802 小时前
原型链、闭包、事件循环等概念,通过手写代码题验证理解深度
前端·javascript