更新记录
1.0.1(2026-07-25)
优化
- 优化请求日志数据结构,
data 字段中补充 method 和 url,与完成日志保持信息一致
- 统一状态文本格式:
HTTP错误(${statusCode}),与 业务错误(${bizCode}) 风格保持一致
- 优化日志输出示例,补充请求日志和请求取消场景的示例
修复
- 修复请求取消时
res.statusCode 为 undefined 的处理,显式判断避免误判
1.0.0(2026-07-22)
新增
- 首次发布请求日志插件
- 基于
useComplete 完成拦截器实现,记录所有请求(含网络超时、无网络等异常情况)
- 自动适配
mh-request 全局配置:
apiFieldMap:自动识别 code / msg 字段名
successCode:判断业务是否成功
httpSuccessCodes:判断 HTTP 状态是否成功
- 智能日志分级:
info:请求成功(HTTP 成功且业务成功)
warn:业务错误(HTTP 成功但业务 code 不匹配)
error:HTTP 错误(含超时、无网络、5xx 等)
- 支持配置项:
logLevel:控制日志输出级别(debug / info / warn / error)
customLogger:自定义日志输出函数,支持上报到服务器
excludeUrls:按 URL 排除日志(支持字符串或正则)
maxLogSize:限制内存日志存储条数,防止内存泄漏
- 提供
getLoggerHistory() 方法,方便调试时查看最近日志
- 请求拦截器记录请求开始时间,便于计算耗时
- 响应日志包含状态码、耗时、业务数据、业务状态等完整信息
平台兼容性
uni-app(3.8.0)
| Vue2 |
Vue3 |
Chrome |
Safari |
app-vue |
app-nvue |
Android |
iOS |
鸿蒙 |
| √ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
| 微信小程序 |
支付宝小程序 |
抖音小程序 |
百度小程序 |
快手小程序 |
京东小程序 |
鸿蒙元服务 |
QQ小程序 |
飞书小程序 |
小红书小程序 |
快应用-华为 |
快应用-联盟 |
| √ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
√ |
uni-app x(3.8.0)
| Chrome |
Safari |
Android |
iOS |
鸿蒙 |
微信小程序 |
| √ |
√ |
√ |
√ |
√ |
√ |
mh-request-logger
基于 mh-request 的请求日志插件,记录所有请求(含网络异常)的完整信息,支持自定义日志输出和上报。
本插件是 mh-request 的配套插件,需配合使用。
特性
- 📝 全量记录:无论请求成功或失败(含超时、无网络等)都能记录
- 🔧 自动适配:自动读取全局
apiFieldMap、successCode、httpSuccessCodes,与核心库行为一致
- 🎯 智能分级:自动区分 HTTP 错误、业务错误、成功响应,使用不同日志级别
- 🚫 灵活过滤:支持按 URL 排除日志(字符串包含或正则匹配)
- 🎨 可定制输出:支持自定义日志函数,便于接入监控平台或上报服务器
- 💾 内存管理:支持限制日志存储条数,防止内存泄漏
- 🐛 调试友好:提供
getLoggerHistory() 方法,随时查看最近日志
快速开始
import { Request } from '@/uni_modules/mh-request'
import { loggerPlugin } from '@/uni_modules/mh-request-logger'
const request = new Request({
baseURL: 'https://api.example.com',
plugins: [
{ plugin: loggerPlugin }
]
})
export default request
自定义日志输出
const request = new Request({
baseURL: 'https://api.example.com',
plugins: [
{
plugin: loggerPlugin,
config: {
logLevel: 'warn',
customLogger: (level, message, data) => {
// 接入自定义日志系统或上报到服务器
myLogSystem.report({ level, message, data })
}
}
}
]
})
排除特定接口
const request = new Request({
baseURL: 'https://api.example.com',
plugins: [
{
plugin: loggerPlugin,
config: {
excludeUrls: [
'/health', // 字符串包含匹配
/^\/api\/ping/, // 正则匹配
]
}
}
]
})
配置项
LoggerConfig
| 属性 |
类型 |
默认值 |
说明 |
logLevel |
'debug' | 'info' | 'warn' | 'error' |
'info' |
日志输出级别,低于该级别的日志将被过滤 |
customLogger |
(level, message, data) => void |
console.log |
自定义日志输出函数,可用于上报或集成第三方日志系统 |
excludeUrls |
(string | RegExp)[] |
[] |
排除的 URL 列表,匹配的请求不记录任何日志 |
maxLogSize |
number |
1000 |
内存中保留的最大日志条数,超出后移除最早记录 |
日志级别说明
| 级别 |
优先级 |
输出场景 |
debug |
0 |
所有请求(含请求体等详细信息) |
info |
1 |
成功请求(HTTP 成功且业务成功) |
warn |
2 |
业务错误(HTTP 成功但业务 code ≠ successCode) |
error |
3 |
HTTP 错误(含超时、无网络、5xx 等) |
工作原理
日志记录流程
请求发起 → 请求拦截器记录开始时间 → 发送请求
↓
请求完成(成功或失败)→ 完成拦截器触发
↓
判断 HTTP 状态(使用 httpSuccessCodes)
↓
成功 → 解析业务数据 → 判断业务 code(使用 apiFieldMap)
↓
业务成功 → info 级别日志
业务失败 → warn 级别日志
HTTP 失败 → error 级别日志
↓
输出日志(customLogger 或 console)
↓
存入内存历史(受 maxLogSize 限制)
高级用法
上报到监控平台(注意脱敏)
⚠️ 重要提醒:上报日志到服务器时,务必对请求/响应中的敏感字段进行脱敏处理,避免泄露用户密码、Token、身份证号、手机号等隐私信息。
const request = new Request({
baseURL: 'https://api.example.com',
plugins: [
{
plugin: loggerPlugin,
config: {
logLevel: 'error', // 仅上报错误日志
customLogger: (level, message, data) => {
// 脱敏处理:移除或隐藏敏感字段
const sanitized = sanitizeData(data)
// 上报到 Sentry / 阿里云 ARMS 等监控平台
Sentry.captureMessage(message, { level, extra: sanitized })
}
}
}
]
})
/**
* 数据脱敏函数 - 递归移除敏感字段
*/
function sanitizeData(data: any): any {
if (!data || typeof data !== 'object') return data
const sensitiveKeys = ['password', 'token', 'authorization', 'phone', 'idCard', 'secret']
const result = Array.isArray(data) ? [] : {}
for (const [key, value] of Object.entries(data)) {
if (sensitiveKeys.some(k => k.toLowerCase() === key.toLowerCase())) {
result[key] = '***'
continue
}
if (value && typeof value === 'object') {
result[key] = sanitizeData(value)
} else {
result[key] = value
}
}
return result
}
查看历史日志(调试用)
// 在控制台查看最近日志
const history = request.getLoggerHistory()
console.table(history)
生产环境动态调整日志级别
const isDev = process.env.NODE_ENV === 'development'
const request = new Request({
baseURL: 'https://api.example.com',
plugins: [
{
plugin: loggerPlugin,
config: {
logLevel: isDev ? 'debug' : 'error',
maxLogSize: isDev ? 500 : 50
}
}
]
})
接入第三方日志库
import log4js from 'log4js'
const logger = log4js.getLogger('http')
const request = new Request({
plugins: [
{
plugin: loggerPlugin,
config: {
customLogger: (level, message, data) => {
logger[level](message, data)
}
}
}
]
})
日志输出示例
请求日志
[logger] DEBUG [请求] GET /user/info {
method: 'GET',
url: '/user/info',
data: { id: 1 }
}
成功请求
[logger] INFO [完成] GET /user/info -> 成功 (156ms) {
statusCode: 200,
duration: '156ms',
data: { code: 1, msg: '成功', data: { id: 1, name: '张三' } },
business: { code: 1, msg: '成功', success: true }
}
业务错误
[logger] WARN [完成] POST /order/create -> 业务错误(1001) (203ms) {
statusCode: 200,
duration: '203ms',
data: { code: 1001, msg: '库存不足', data: null },
business: { code: 1001, msg: '库存不足', success: false }
}
网络超时
[logger] ERROR [完成] GET /user/info -> HTTP错误(0) (30002ms) {
statusCode: 0,
duration: '30002ms',
errMsg: 'request:fail timeout'
}
请求取消
[logger] ERROR [完成] GET /user/info -> HTTP错误(N/A) (150ms) {
statusCode: 'N/A',
duration: '150ms',
errMsg: 'request:fail abort'
}