7.1 uni.request 基础
uni.request 是 uni-app 提供的跨端 HTTP 请求 API,在 H5 端封装为 XMLHttpRequest,在 App 端使用原生 HTTP 库,在小程序端调用各平台的网络 API。
// 基础用法(Callback 风格)
uni.request({
url: 'https://api.example.com/users/1',
method: 'GET',
header: {
'Content-Type': 'application/json',
'Authorization': 'Bearer token123'
},
success(res) {
console.log(res.data) // 响应数据
console.log(res.statusCode) // HTTP 状态码
},
fail(err) {
console.error(err)
}
})
// Promise 风格(uni-app 官方支持)
const res = await uni.request({
url: 'https://api.example.com/users/1'
})
console.log(res.data)
小程序合法域名
微信小程序要求所有网络请求的域名必须在微信公众平台的「合法域名」中配置。开发阶段可以在微信开发者工具的「详情 → 本地设置」中勾选"不校验合法域名",但发布前必须正式配置。
7.2 生产级请求封装
直接使用 uni.request 存在很多问题:每次都要写 baseURL、token、错误处理等重复代码。封装一个请求实例是工程化的必要步骤。
// utils/request.ts — 生产级请求封装
import { useUserStore } from '@/stores/user'
// 响应数据格式约定
interface ApiResponse<T = any> {
code: number
message: string
data: T
}
const BASE_URL = import.meta.env.VITE_API_BASE_URL || 'https://api.example.com'
const TIMEOUT = 15000 // 15 秒超时
function request<T = any>(
url: string,
options: Partial<UniApp.RequestOptions> = {}
): Promise<T> {
return new Promise((resolve, reject) => {
const userStore = useUserStore()
// 请求拦截:添加 token
const header: Record<string, string> = {
'Content-Type': 'application/json',
...options.header as Record<string, string>
}
if (userStore.token) {
header['Authorization'] = `Bearer ${userStore.token}`
}
uni.request({
url: `${BASE_URL}${url}`,
timeout: TIMEOUT,
...options,
header,
success(res) {
// 响应拦截:统一处理 HTTP 状态码
if (res.statusCode === 401) {
userStore.logout() // token 过期,强制退出登录
reject(new Error('登录已过期'))
return
}
if (res.statusCode >= 400) {
reject(new Error(`HTTP ${res.statusCode}`))
return
}
const body = res.data as ApiResponse<T>
// 业务错误码处理
if (body.code !== 0) {
uni.showToast({ title: body.message, icon: 'none' })
reject(new Error(body.message))
return
}
resolve(body.data)
},
fail(err) {
// 网络错误(超时、无网络等)
if (err.errMsg?.includes('timeout')) {
uni.showToast({ title: '请求超时,请重试', icon: 'none' })
} else {
uni.showToast({ title: '网络异常,请检查网络', icon: 'none' })
}
reject(err)
}
})
})
}
// 导出 HTTP 方法
export const http = {
get<T>(url: string, params?: Record<string, any>) {
return request<T>(url, { method: 'GET', data: params })
},
post<T>(url: string, data?: Record<string, any>) {
return request<T>(url, { method: 'POST', data })
},
put<T>(url: string, data?: Record<string, any>) {
return request<T>(url, { method: 'PUT', data })
},
delete<T>(url: string) {
return request<T>(url, { method: 'DELETE' })
}
}
// 使用
const user = await http.get<UserInfo>('/api/users/me')
const order = await http.post<Order>('/api/orders', { productId: 42 })
7.3 文件上传与下载
// 选择图片并上传
async function uploadAvatar() {
// 1. 选择图片
const { tempFilePaths } = await uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera']
})
// 2. 显示上传进度
uni.showLoading({ title: '上传中...' })
try {
// 3. 上传文件
const userStore = useUserStore()
const res = await uni.uploadFile({
url: 'https://api.example.com/upload/avatar',
filePath: tempFilePaths[0],
name: 'file',
header: { 'Authorization': `Bearer ${userStore.token}` },
formData: { type: 'avatar' }
})
const data = JSON.parse(res.data) as { url: string }
console.log('上传成功:', data.url)
} finally {
uni.hideLoading()
}
}
// 下载文件并预览
async function downloadPDF(url: string) {
const res = await uni.downloadFile({ url })
if (res.statusCode === 200) {
await uni.openDocument({
filePath: res.tempFilePath,
fileType: 'pdf'
})
}
}
7.4 uniCloud 云开发
uniCloud 是 DCloud 推出的云开发平台,提供数据库、云函数、文件存储等服务,类似微信云开发但跨平台。它让开发者无需自建服务器,即可完成完整的前后端开发。
云函数
云函数是运行在服务端的 JavaScript 函数,可以安全地访问数据库(绕过客户端的安全限制)。
// cloudfunctions/getUserList/index.js
'use strict'
const db = uniCloud.database()
exports.main = async (event, context) => {
// event:客户端传来的参数
// context:请求上下文(uid、appId 等)
const { page = 1, pageSize = 20, keyword } = event
const collection = db.collection('users')
let query = collection
if (keyword) {
// 正则搜索
query = query.where({
name: db.RegExp({ regexp: keyword, options: 'i' })
})
}
const [total, list] = await Promise.all([
query.count(),
query.skip((page - 1) * pageSize).limit(pageSize).get()
])
return {
code: 0,
data: {
list: list.data,
total: total.total,
hasMore: page * pageSize < total.total
}
}
}
在客户端调用云函数
// 调用云函数
const result = await uniCloud.callFunction({
name: 'getUserList',
data: { page: 1, pageSize: 20, keyword: '张' }
})
if (result.result.code === 0) {
list.value = result.result.data.list
}
云数据库直接操作(clientDB)
clientDB 允许客户端直接操作数据库,通过数据库权限规则控制安全性:
// 客户端直接查询(需要在数据库权限中配置允许)
const db = uniCloud.database()
const articles = db.collection('articles')
// 查询列表(分页)
const res = await articles
.where({ status: 'published' })
.orderBy('createTime', 'desc')
.skip(0)
.limit(10)
.field('title,summary,cover,createTime') // 只返回需要的字段
.get()
// 新增文档
await articles.add({
title: '新文章',
content: '...',
status: 'draft',
createTime: db.serverDate() // 服务器时间
})
// 更新文档
await articles.doc('articleId123').update({
views: db.command.inc(1) // 原子操作:浏览量 +1
})
7.5 数据缓存策略
合理的缓存策略可以显著改善用户体验(快速显示内容)并减少不必要的网络请求:
// composables/useRequest.ts — 带缓存的请求 Composable
import { ref } from 'vue'
import { http } from '@/utils/request'
import { storage } from '@/utils/storage'
interface CacheItem<T> {
data: T
expireAt: number
}
export function useRequest<T>(
cacheKey: string,
fetcher: () => Promise<T>,
ttl = 5 * 60 * 1000 // 默认缓存 5 分钟
) {
const data = ref<T | null>(null)
const loading = ref(false)
const error = ref<Error | null>(null)
async function fetch(force = false) {
// 检查缓存
if (!force) {
const cached = storage.get<CacheItem<T>>(cacheKey)
if (cached && Date.now() < cached.expireAt) {
data.value = cached.data
return
}
}
loading.value = true
error.value = null
try {
data.value = await fetcher()
// 写入缓存
storage.set(cacheKey, { data: data.value, expireAt: Date.now() + ttl })
} catch (e) {
error.value = e as Error
} finally {
loading.value = false
}
}
return { data, loading, error, fetch }
}
// 使用
const { data: banners, loading, fetch } = useRequest(
'home_banners',
() => http.get<Banner[]>('/api/banners'),
10 * 60 * 1000 // 缓存 10 分钟
)
onLoad(() => fetch())
7.6 小结
- 封装统一的 HTTP 请求层,处理 baseURL、token、错误提示,避免重复代码
- 请求拦截器注入 token,响应拦截器处理 401(token 过期)和业务错误码
- uniCloud 提供了完整的 Serverless 方案:云函数 + 云数据库 + 文件存储
- clientDB 让客户端直接操作数据库,安全性通过权限规则配置
- 缓存策略:先读缓存显示内容,后台静默刷新,提升首屏速度
- 文件上传使用
uni.uploadFile,注意与uni.request的区别(不同 API)