<think>我们需要实现一个请求统一处理模块,用于管理微信小程序中的所有网络请求。主要功能包括:1.统一请求URL配置2.请求头统一处理(如添加token)3.请求和响应拦截器4.错误统一处理5.封装成Promise风格在微信小程序中,网络请求使用`wx.request`,我们将基于它进行封装。步骤:1.创建一个request.js文件,用于封装请求方法。2.定义基础URL、请求拦截器、响应拦截器。3.封装一个request函数,用于处理请求前和请求后的拦截逻辑。4.提供get、post、put、delete等方法。注意:微信小程序不支持全局拦截器,因此我们需要手动在每个请求前后执行拦截器逻辑。</think>
以下是一个完整的微信小程序请求统一处理JS模块的实现方案,包含请求拦截、响应拦截、统一错误处理和Token管理等功能:
```javascript
// utils/request.js
const BASE_URL = 'https://your-api-domain.com/api' // 替换为实际API地址
// 请求队列(用于后续取消请求功能)
const requestQueue = []
// 请求配置
const config = {
tokenKey: 'Authorization',
token: null,
timeout: 10000
}
/**
* 设置请求配置
* @param {Object} cfg 配置对象
*/
export function setConfig(cfg) {
Object.assign(config, cfg)
}
/**
* 获取本地存储的Token
*/
function getToken() {
return config.token || wx.getStorageSync('token')
}
/**
* 请求统一处理
* @param {Object} options 请求参数
* @param {boolean} [useToken=true] 是否携带token
*/
function request(options = {}, useToken = true) {
// 创建请求唯一标识
const requestId = `${Date.now()}_${Math.random().toString(36).substr(2, 6)}`
// 构建请求参数
const requestConfig = Object.assign({
url: '',
method: 'GET',
data: {},
header: {
'Content-Type': 'application/json'
},
timeout: config.timeout,
requestId // 添加请求ID
}, options)
// 请求拦截器
requestInterceptor(requestConfig)
// 添加Token
if (useToken && getToken()) {
requestConfig.header[config.tokenKey] = `Bearer ${getToken()}`
}
// 添加到请求队列
requestQueue.push(requestConfig)
// 发起请求
return new Promise((resolve, reject) => {
wx.request({
...requestConfig,
success: (res) => {
// 响应拦截器
const interceptedRes = responseInterceptor(res)
if (interceptedRes) {
resolve(interceptedRes)
}
},
fail: (err) => {
// 错误处理
errorHandler(err, requestConfig)
reject(err)
},
complete: () => {
// 从请求队列中移除
const index = requestQueue.findIndex(req => req.requestId === requestId)
if (index !== -1) {
requestQueue.splice(index, 1)
}
}
})
})
}
/**
* 请求拦截器
* @param {Object} config 请求配置
*/
function requestInterceptor(config) {
// 可以在这里添加全局参数
// console.log('请求拦截器: ', config)
// 示例:全局添加时间戳
if (config.method === 'GET') {
config.url += (config.url.includes('?') ? '&' : '?') + `_t=${Date.now()}`
}
// 示例:显示加载状态
if (config.showLoading) {
wx.showLoading({ title: '加载中...', mask: true })
}
return config
}
/**
* 响应拦截器
* @param {Object} response 响应对象
*/
function responseInterceptor(response) {
// console.log('响应拦截器: ', response)
// 关闭加载状态
if (response.config && response.config.showLoading) {
wx.hideLoading()
}
const { statusCode, data } = response
// 根据状态码处理
if (statusCode === 200) {
// 处理服务端错误码
if (data && data.code !== 0) {
handleServerError(data)
return null
}
return data
}
// 处理HTTP错误
handleHttpError(statusCode)
return null
}
/**
* 错误处理
* @param {Object} err 错误对象
* @param {Object} config 请求配置
*/
function errorHandler(err, config) {
// console.error('请求错误: ', err)
// 关闭加载状态
if (config.showLoading) {
wx.hideLoading()
}
// 错误提示
let errMsg = '网络错误,请重试'
if (err.errMsg.includes('timeout')) {
errMsg = '请求超时,请检查网络连接'
} else if (err.errMsg.includes('fail to create request')) {
errMsg = '无效的请求地址'
}
wx.showToast({
title: errMsg,
icon: 'none',
duration: 2000
})
// 处理需要登录的错误
if (config.handleLogin) {
wx.navigateTo({ url: '/pages/login/login' })
}
}
/**
* 处理服务端错误
* @param {Object} data 响应数据
*/
function handleServerError(data) {
const { code, message } = data
let errMsg = message || '服务端错误'
// 根据错误码定制处理逻辑
switch (code) {
case 401: // 未授权
wx.navigateTo({ url: '/pages/login/login' })
errMsg = '请重新登录'
break
case 403: // 禁止访问
errMsg = '无访问权限'
break
case 500: // 服务器错误
errMsg = '服务端繁忙'
break
default:
break
}
wx.showToast({ title: errMsg, icon: 'none' })
}
/**
* 处理HTTP错误
* @param {number} statusCode HTTP状态码
*/
function handleHttpError(statusCode) {
let errMsg = '请求错误'
switch (statusCode) {
case 400:
errMsg = '请求参数错误'
break
case 404:
errMsg = '资源不存在'
break
case 500:
errMsg = '服务器内部错误'
break
case 502:
errMsg = '网关错误'
break
}
wx.showToast({ title: errMsg, icon: 'none' })
}
/**
* 中断所有请求
*/
export function cancelAllRequests() {
requestQueue.forEach(request => {
if (request.abort) {
request.abort()
}
})
requestQueue.length = 0
}
/**
* 中断特定请求
* @param {string} requestId 请求ID
*/
export function cancelRequest(requestId) {
const index = requestQueue.findIndex(req => req.requestId === requestId)
if (index !== -1 && requestQueue[index].abort) {
requestQueue[index].abort()
requestQueue.splice(index, 1)
}
}
// 导出常用方法
export function get(url, params = {}, options = {}) {
return request({
url,
method: 'GET',
data: params,
...options
})
}
export function post(url, data = {}, options = {}) {
return request({
url,
method: 'POST',
data,
...options
})
}
export function put(url, data = {}, options = {}) {
return request({
url,
method: 'PUT',
data,
...options
})
}
export function del(url, data = {}, options = {}) {
return request({
url,
method: 'DELETE',
data,
...options
})
}
export default request
```
### 模块功能详解
1. **请求统一入口**:
- `request()`方法封装了所有请求逻辑,返回Promise
- 支持GET/POST/PUT/DELETE方法封装
2. **请求拦截器**:
- 自动添加时间戳防缓存
- 自动添加Authorization头携带Token
- 显示加载状态(可选)
3. **响应拦截器**:
- 根据HTTP状态码统一处理错误
- 根据服务端业务码处理错误(如401重定向登录)
- 自动隐藏加载状态
4. **错误处理**:
- 网络错误处理(超时、链接失败等)
- HTTP状态码处理(4xx/5xx)
- 业务状态码处理(自定义错误码)
5. **请求管理**:
- 请求队列管理
- 取消特定请求功能
- 取消所有请求功能
6. **配置管理**:
- 设置基础API地址
- 配置请求超时时间
- 配置Token存储方式
### 使用示例
```javascript
// 在页面中引入
import { post, get } from '/utils/request'
Page({
// 获取用户信息
async getUserInfo() {
try {
const res = await get('/user/info', {
id: 123
}, {
showLoading: true, // 显示加载状态
handleLogin: true // 自动处理登录过期
})
console.log('用户信息:', res)
} catch (error) {
console.error('获取用户信息失败', error)
}
},
// 更新用户信息
async updateUserInfo(userData) {
try {
const res = await post('/user/update', userData)
wx.showToast({ title: '更新成功' })
return res
} catch (error) {
// 错误已统一处理,这里可追加特定处理
}
}
})
```
### 在app.js中全局配置
```javascript
// app.js
import { setConfig } from './utils/request'
App({
onLaunch() {
// 设置请求配置
setConfig({
token: 'your_token_value', // 从存储获取或登录后设置
tokenKey: 'X-Access-Token',
timeout: 15000
})
},
globalData: {
// 可以在这里暴露request方法
request: require('./utils/request')
}
})
```
### 最佳实践
1. **Token管理**:
- 登录成功后存储Token:`wx.setStorageSync('token', res.data.token)`
- 退出登录时清除:`wx.removeStorageSync('token')`
2. **响应格式约定**:
```json
{
"code": 0, // 0表示成功,非0表示错误
"msg": "成功",
"data": {} // 业务数据
}
```
3. **自定义配置**:
```javascript
// 特定请求隐藏错误提示
get('/data', {}, { showError: false })
// 特定请求携带不同Token
get('/admin/data', {}, {
token: 'special_admin_token'
})
```