You've already forked uniapp-error-monitor
文档 更新README和使用示例,添加错误级别控制和去重功能说明
This commit is contained in:
150
README.md
150
README.md
@@ -11,16 +11,29 @@
|
|||||||
## ✨ 核心特性
|
## ✨ 核心特性
|
||||||
|
|
||||||
- 🎯 **零配置使用**: 开箱即用,支持多种导入方式
|
- 🎯 **零配置使用**: 开箱即用,支持多种导入方式
|
||||||
|
|
||||||
- 🔍 **全面错误捕获**: 全局错误、Promise错误、控制台错误、网络错误、小程序错误
|
- 🔍 **全面错误捕获**: 全局错误、Promise错误、控制台错误、网络错误、小程序错误
|
||||||
|
|
||||||
- 🧠 **环境智能**: 自动检测生产环境,非生产环境优雅降级
|
- 🧠 **环境智能**: 自动检测生产环境,非生产环境优雅降级
|
||||||
|
|
||||||
- ⚡ **高性能**: 异步发送错误,不阻塞主线程
|
- ⚡ **高性能**: 异步发送错误,不阻塞主线程
|
||||||
|
|
||||||
- 🔄 **重试机制**: 网络失败自动重试,可配置次数和间隔
|
- 🔄 **重试机制**: 网络失败自动重试,可配置次数和间隔
|
||||||
|
|
||||||
- 📊 **错误统计**: 内置统计功能,便于数据分析
|
- 📊 **错误统计**: 内置统计功能,便于数据分析
|
||||||
|
|
||||||
- 🔧 **高度可定制**: 支持自定义发送器和格式化函数
|
- 🔧 **高度可定制**: 支持自定义发送器和格式化函数
|
||||||
|
|
||||||
- 📱 **全平台支持**: H5、微信小程序、App、支付宝小程序等
|
- 📱 **全平台支持**: H5、微信小程序、App、支付宝小程序等
|
||||||
|
|
||||||
- 🛡️ **类型安全**: 完整的 TypeScript 类型定义
|
- 🛡️ **类型安全**: 完整的 TypeScript 类型定义
|
||||||
|
|
||||||
- 📦 **多格式输出**: 支持 ESM、CommonJS、UMD 格式
|
- 📦 **多格式输出**: 支持 ESM、CommonJS、UMD 格式
|
||||||
|
|
||||||
|
- 🎚️ **错误级别控制**: 支持 strict/standard/silent 三种监控模式
|
||||||
|
|
||||||
|
- 🔄 **错误去重**: 相同错误在指定间隔内只上报一次,避免重复告警
|
||||||
|
|
||||||
## 📦 安装
|
## 📦 安装
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -36,33 +49,61 @@ pnpm add uniapp-error-monitor
|
|||||||
|
|
||||||
## 🚀 快速开始
|
## 🚀 快速开始
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### 方式一:命名导出(推荐)
|
### 方式一:命名导出(推荐)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { initErrorMonitor, reportError, getErrorStats, wrapPromise } from 'uniapp-error-monitor'
|
|
||||||
|
import {
|
||||||
|
initErrorMonitor,
|
||||||
|
reportError,
|
||||||
|
getErrorStats,
|
||||||
|
wrapPromise,
|
||||||
|
setErrorLevel,
|
||||||
|
clearErrorCache,
|
||||||
|
ERROR_LEVEL
|
||||||
|
} from 'uniapp-error-monitor'
|
||||||
|
|
||||||
|
|
||||||
// 初始化错误监控
|
// 初始化错误监控
|
||||||
initErrorMonitor({
|
initErrorMonitor({
|
||||||
webhookUrl: 'https://your-webhook-url.com', // 必填
|
webhookUrl: 'https://your-webhook-url.com', // 必填
|
||||||
enableGlobalError: true, // 启用全局错误捕获
|
enableGlobalError: true, // 启用全局错误捕获
|
||||||
enablePromiseError: true, // 启用 Promise 错误捕获
|
enablePromiseError: true, // 启用 Promise 错误捕获
|
||||||
enableConsoleError: false, // 禁用 console.error 捕获
|
enableConsoleError: false, // 禁用 console.error 捕获
|
||||||
|
errorLevel: ERROR_LEVEL.STRICT, // 错误级别:strict/standard/silent
|
||||||
|
dedupInterval: 60000, // 错误去重间隔(毫秒),默认1分钟
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// 设置错误级别(可选)
|
||||||
|
setErrorLevel(ERROR_LEVEL.STANDARD) // 切换为标准模式
|
||||||
|
|
||||||
|
|
||||||
// 手动上报错误
|
// 手动上报错误
|
||||||
reportError('manual', new Error('自定义错误'), {
|
reportError('manual', new Error('自定义错误'), {
|
||||||
page: 'index',
|
page: 'index',
|
||||||
action: '用户操作失败'
|
action: '用户操作失败'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
// Promise 包装(自动捕获 Promise 错误)
|
// Promise 包装(自动捕获 Promise 错误)
|
||||||
const result = await wrapPromise(
|
const result = await wrapPromise(
|
||||||
fetch('https://api.example.com/data')
|
fetch('https://api.example.com/data')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
// 获取错误统计
|
// 获取错误统计
|
||||||
const stats = getErrorStats()
|
const stats = getErrorStats()
|
||||||
console.log('错误统计:', stats)
|
console.log('错误统计:', stats)
|
||||||
|
|
||||||
|
|
||||||
|
// 清空错误去重缓存(可选)
|
||||||
|
clearErrorCache()
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 方式二:类实例(高级用法)
|
### 方式二:类实例(高级用法)
|
||||||
@@ -116,25 +157,71 @@ ErrorMonitor.reportError('manual', new Error('测试错误'))
|
|||||||
|
|
||||||
## ⚙️ 配置选项
|
## ⚙️ 配置选项
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
|
||||||
interface ErrorMonitorOptions {
|
interface ErrorMonitorOptions {
|
||||||
// 基础配置
|
// 基础配置
|
||||||
webhookUrl?: string // Webhook 地址(可选,使用环境变量)
|
webhookUrl?: string // Webhook 地址(可选,使用环境变量)
|
||||||
enableGlobalError?: boolean // 启用全局错误捕获(默认:true)
|
enableGlobalError?: boolean // 启用全局错误捕获(默认:true)
|
||||||
enablePromiseError?: boolean // 启用 Promise 错误捕获(默认:true)
|
enablePromiseError?: boolean // 启用 Promise 错误捕获(默认:true)
|
||||||
enableConsoleError?: boolean // 启用 console.error 捕获(默认:false)
|
enableConsoleError?: boolean // 启用 console.error 捕获(默认:false)
|
||||||
|
|
||||||
|
|
||||||
|
// 错误级别配置
|
||||||
|
errorLevel?: 'strict' | 'standard' | 'silent' // 错误级别(默认:silent)
|
||||||
|
|
||||||
|
|
||||||
|
// 错误去重配置
|
||||||
|
dedupInterval?: number // 相同错误去重间隔(ms)(默认:60000,即1分钟)
|
||||||
|
|
||||||
|
|
||||||
// 重试配置
|
// 重试配置
|
||||||
maxRetries?: number // 最大重试次数(默认:3)
|
maxRetries?: number // 最大重试次数(默认:3)
|
||||||
retryDelay?: number // 重试延迟时间(ms)(默认:1000)
|
retryDelay?: number // 重试延迟时间(ms)(默认:1000)
|
||||||
|
|
||||||
|
|
||||||
// 高级配置
|
// 高级配置
|
||||||
forceEnable?: boolean // 强制启用错误监控(忽略环境检查)
|
forceEnable?: boolean // 强制启用错误监控(忽略环境检查)
|
||||||
sender?: (errorInfo: ErrorInfo) => Promise<void> // 自定义发送器
|
sender?: (errorInfo: ErrorInfo) => Promise<void> // 自定义发送器
|
||||||
formatter?: (errorInfo: ErrorInfo) => string // 自定义格式化函数
|
formatter?: (errorInfo: ErrorInfo) => string // 自定义格式化函数
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 错误级别说明
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| 级别 | 说明 | 监控范围 |
|
||||||
|
|
||||||
|
|------|------|----------|
|
||||||
|
|
||||||
|
| `strict` | 严格模式 | 监控所有错误(global、promise、console、miniProgram、api、network) |
|
||||||
|
|
||||||
|
| `standard` | 标准模式 | 监控基本错误(global、promise、miniProgram) |
|
||||||
|
|
||||||
|
| `silent` | 静默模式 | 仅监控严重错误(miniProgram、pageNotFound) |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### 错误严重程度分类
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
| 严重程度 | 错误类型 |
|
||||||
|
|
||||||
|
|----------|----------|
|
||||||
|
|
||||||
|
| **critical** (严重) | miniProgram, pageNotFound |
|
||||||
|
|
||||||
|
| **normal** (普通) | global, promise, api, network, manual |
|
||||||
|
|
||||||
|
| **minor** (轻微) | console |
|
||||||
|
|
||||||
## 📊 错误类型
|
## 📊 错误类型
|
||||||
|
|
||||||
| 类型 | 说明 | 自动捕获 | 手动上报 | 触发场景 |
|
| 类型 | 说明 | 自动捕获 | 手动上报 | 触发场景 |
|
||||||
@@ -173,6 +260,35 @@ resetErrorStats()
|
|||||||
console.log('错误统计已重置')
|
console.log('错误统计已重置')
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 错误级别控制
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { setErrorLevel, getErrorLevel, ERROR_LEVEL } from 'uniapp-error-monitor'
|
||||||
|
|
||||||
|
// 获取当前错误级别
|
||||||
|
const currentLevel = getErrorLevel()
|
||||||
|
console.log('当前错误级别:', currentLevel)
|
||||||
|
|
||||||
|
// 设置错误级别
|
||||||
|
setErrorLevel(ERROR_LEVEL.STRICT) // 严格模式:监控所有错误
|
||||||
|
setErrorLevel(ERROR_LEVEL.STANDARD) // 标准模式:监控基本错误
|
||||||
|
setErrorLevel(ERROR_LEVEL.SILENT) // 静默模式:仅监控严重错误
|
||||||
|
```
|
||||||
|
|
||||||
|
### 错误去重管理
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { clearErrorCache } from 'uniapp-error-monitor'
|
||||||
|
|
||||||
|
// 清空错误去重缓存(允许相同错误重新上报)
|
||||||
|
clearErrorCache()
|
||||||
|
|
||||||
|
// 去重机制说明:
|
||||||
|
// - 相同错误在 dedupInterval 间隔内只会被上报一次
|
||||||
|
// - 默认间隔为 60 秒(60000ms)
|
||||||
|
// - 可通过配置 dedupInterval 自定义间隔时间
|
||||||
|
```
|
||||||
|
|
||||||
### 丰富的错误上下文
|
### 丰富的错误上下文
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
@@ -216,33 +332,51 @@ setInterval(() => {
|
|||||||
|
|
||||||
## 🛡️ TypeScript 支持
|
## 🛡️ TypeScript 支持
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
完整的类型安全支持:
|
完整的类型安全支持:
|
||||||
|
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ErrorMonitorOptions,
|
ErrorMonitorOptions,
|
||||||
ErrorType,
|
ErrorType,
|
||||||
ErrorStats,
|
ErrorStats,
|
||||||
EnvironmentInfo,
|
EnvironmentInfo,
|
||||||
ErrorInfo
|
ErrorInfo
|
||||||
} from 'uniapp-error-monitor'
|
} from 'uniapp-error-monitor'
|
||||||
|
|
||||||
|
import {
|
||||||
|
initErrorMonitor,
|
||||||
|
reportError,
|
||||||
|
setErrorLevel,
|
||||||
|
ERROR_LEVEL
|
||||||
|
} from 'uniapp-error-monitor'
|
||||||
|
|
||||||
|
|
||||||
// 类型安全的配置
|
// 类型安全的配置
|
||||||
|
|
||||||
const options: ErrorMonitorOptions = {
|
const options: ErrorMonitorOptions = {
|
||||||
webhookUrl: 'https://example.com/webhook',
|
webhookUrl: 'https://example.com/webhook',
|
||||||
enableGlobalError: true,
|
enableGlobalError: true,
|
||||||
enablePromiseError: true,
|
enablePromiseError: true,
|
||||||
|
errorLevel: ERROR_LEVEL.STRICT,
|
||||||
|
dedupInterval: 60000,
|
||||||
maxRetries: 5,
|
maxRetries: 5,
|
||||||
retryDelay: 2000,
|
retryDelay: 2000,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 类型安全的错误上报
|
// 类型安全的错误上报
|
||||||
|
|
||||||
const reportTypeSafeError = (type: ErrorType, message: string) => {
|
const reportTypeSafeError = (type: ErrorType, message: string) => {
|
||||||
reportError(type, new Error(message), {
|
reportError(type, new Error(message), {
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
userId: '12345'
|
userId: '12345'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 📱 平台兼容性
|
## 📱 平台兼容性
|
||||||
|
|||||||
@@ -12,17 +12,23 @@ import {
|
|||||||
initErrorMonitor,
|
initErrorMonitor,
|
||||||
reportError,
|
reportError,
|
||||||
getErrorStats,
|
getErrorStats,
|
||||||
wrapPromise
|
wrapPromise,
|
||||||
|
setErrorLevel,
|
||||||
|
getErrorLevel,
|
||||||
|
clearErrorCache,
|
||||||
|
ERROR_LEVEL
|
||||||
} from 'uniapp-error-monitor'
|
} from 'uniapp-error-monitor'
|
||||||
|
|
||||||
// 初始化错误监控
|
// 初始化错误监控
|
||||||
initErrorMonitor({
|
initErrorMonitor({
|
||||||
webhookUrl: 'https://your-webhook-url.com', // 必填
|
webhookUrl: 'https://your-webhook-url.com', // 必填
|
||||||
enableGlobalError: true, // 启用全局错误捕获
|
enableGlobalError: true, // 启用全局错误捕获
|
||||||
enablePromiseError: true, // 启用 Promise 错误捕获
|
enablePromiseError: true, // 启用 Promise 错误捕获
|
||||||
enableConsoleError: false, // 禁用 console.error 捕获
|
enableConsoleError: false, // 禁用 console.error 捕获
|
||||||
maxRetries: 3, // 最大重试次数
|
errorLevel: ERROR_LEVEL.STRICT, // 错误级别:strict/standard/silent
|
||||||
retryDelay: 1000, // 重试延迟时间(ms)
|
dedupInterval: 60000, // 错误去重间隔(毫秒),默认1分钟
|
||||||
|
maxRetries: 3, // 最大重试次数
|
||||||
|
retryDelay: 1000, // 重试延迟时间(ms)
|
||||||
})
|
})
|
||||||
|
|
||||||
// 手动上报错误
|
// 手动上报错误
|
||||||
@@ -104,37 +110,73 @@ ErrorMonitorDefault.initErrorMonitor({
|
|||||||
ErrorMonitorDefault.reportError('manual', new Error('测试错误'))
|
ErrorMonitorDefault.reportError('manual', new Error('测试错误'))
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
// 4. TypeScript 类型安全使用
|
// 4. TypeScript 类型安全使用
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
|
|
||||||
ErrorMonitorOptions,
|
ErrorMonitorOptions,
|
||||||
|
|
||||||
ErrorType,
|
ErrorType,
|
||||||
ErrorStats,
|
|
||||||
|
ErrorStats,
|
||||||
|
|
||||||
EnvironmentInfo
|
EnvironmentInfo
|
||||||
|
|
||||||
} from 'uniapp-error-monitor'
|
} from 'uniapp-error-monitor'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 类型安全的配置
|
// 类型安全的配置
|
||||||
|
|
||||||
const options: ErrorMonitorOptions = {
|
const options: ErrorMonitorOptions = {
|
||||||
|
|
||||||
webhookUrl: 'https://example.com/webhook',
|
webhookUrl: 'https://example.com/webhook',
|
||||||
|
|
||||||
enableGlobalError: true,
|
enableGlobalError: true,
|
||||||
|
|
||||||
enablePromiseError: true,
|
enablePromiseError: true,
|
||||||
|
|
||||||
|
errorLevel: ERROR_LEVEL.STRICT,
|
||||||
|
|
||||||
|
dedupInterval: 60000,
|
||||||
|
|
||||||
maxRetries: 5,
|
maxRetries: 5,
|
||||||
|
|
||||||
retryDelay: 2000,
|
retryDelay: 2000,
|
||||||
|
|
||||||
forceEnable: false
|
forceEnable: false
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 类型安全的错误上报
|
// 类型安全的错误上报
|
||||||
|
|
||||||
const reportTypeSafeError = (type: ErrorType, message: string) => {
|
const reportTypeSafeError = (type: ErrorType, message: string) => {
|
||||||
|
|
||||||
reportError(type, new Error(message), {
|
reportError(type, new Error(message), {
|
||||||
|
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
|
|
||||||
userId: '12345'
|
userId: '12345'
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 类型安全的统计获取
|
// 类型安全的统计获取
|
||||||
|
|
||||||
const getSafeStats = (): ErrorStats => {
|
const getSafeStats = (): ErrorStats => {
|
||||||
|
|
||||||
return getErrorStats()
|
return getErrorStats()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -216,15 +258,49 @@ reportError('global', new Error('页面崩溃'), {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// 8. 批量错误处理
|
// 9. 错误级别控制
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// 获取当前错误级别
|
||||||
|
const currentLevel = getErrorLevel()
|
||||||
|
console.log('当前错误级别:', currentLevel)
|
||||||
|
|
||||||
|
// 设置错误级别
|
||||||
|
setErrorLevel(ERROR_LEVEL.STRICT) // 严格模式:监控所有错误
|
||||||
|
setErrorLevel(ERROR_LEVEL.STANDARD) // 标准模式:监控基本错误
|
||||||
|
setErrorLevel(ERROR_LEVEL.SILENT) // 静默模式:仅监控严重错误
|
||||||
|
|
||||||
|
// 错误级别说明:
|
||||||
|
// - strict: 监控所有错误(global, promise, console, miniProgram, api, network)
|
||||||
|
// - standard: 监控基本错误(global, promise, miniProgram)
|
||||||
|
// - silent: 仅监控严重错误(miniProgram, pageNotFound)
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 10. 错误去重管理
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
// 清空错误去重缓存(允许相同错误重新上报)
|
||||||
|
clearErrorCache()
|
||||||
|
|
||||||
|
// 去重机制说明:
|
||||||
|
// - 相同错误在 dedupInterval 间隔内只会被上报一次
|
||||||
|
// - 默认间隔为 60 秒(60000ms)
|
||||||
|
// - 可通过配置 dedupInterval 自定义间隔时间
|
||||||
|
|
||||||
|
// 示例:配置更短的去重间隔
|
||||||
|
initErrorMonitor({
|
||||||
|
webhookUrl: 'https://your-webhook-url.com',
|
||||||
|
dedupInterval: 30000, // 30秒去重间隔
|
||||||
|
})
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// 11. 批量错误处理
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
||||||
// 重置错误统计(在页面刷新或特定事件后)
|
// 重置错误统计(在页面刷新或特定事件后)
|
||||||
const resetStats = () => {
|
import { resetErrorStats } from 'uniapp-error-monitor'
|
||||||
import { resetErrorStats } from 'uniapp-error-monitor'
|
resetErrorStats()
|
||||||
resetErrorStats()
|
console.log('错误统计已重置')
|
||||||
console.log('错误统计已重置')
|
|
||||||
}
|
|
||||||
|
|
||||||
// 定时检查错误状态
|
// 定时检查错误状态
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "uniapp-error-monitor",
|
"name": "uniapp-error-monitor",
|
||||||
"version": "1.1.1",
|
"version": "1.2.1",
|
||||||
"description": "专门为UniApp环境设计的错误监控和上报工具,支持全局错误捕获、Promise错误捕获、网络错误捕获等",
|
"description": "专门为UniApp环境设计的错误监控和上报工具,支持全局错误捕获、Promise错误捕获、网络错误捕获等",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"module": "dist/index.esm.js",
|
"module": "dist/index.esm.js",
|
||||||
|
|||||||
199
test/webhook-test.js
Normal file
199
test/webhook-test.js
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
/**
|
||||||
|
* Webhook 真实发送测试
|
||||||
|
* 运行方式:node test/webhook-test.js
|
||||||
|
*/
|
||||||
|
|
||||||
|
const https = require('https')
|
||||||
|
|
||||||
|
// 测试用的 webhook 地址
|
||||||
|
const TEST_WEBHOOK = 'https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=9a401eb2-065a-4882-82e9-b438bcd1eac4'
|
||||||
|
|
||||||
|
// 模拟 uni 环境(使用真实的 HTTP 请求)
|
||||||
|
global.uni = {
|
||||||
|
getSystemInfoSync: () => ({
|
||||||
|
appName: '错误监控测试',
|
||||||
|
appVersion: '1.0.0',
|
||||||
|
platform: 'node',
|
||||||
|
system: 'Node.js ' + process.version,
|
||||||
|
model: 'Server',
|
||||||
|
mode: 'test',
|
||||||
|
}),
|
||||||
|
|
||||||
|
// 使用真实的 HTTPS 请求
|
||||||
|
request: (options) => {
|
||||||
|
console.log('\n========================================')
|
||||||
|
console.log('📤 发送真实请求到 Webhook')
|
||||||
|
console.log('========================================')
|
||||||
|
console.log('URL:', options.url)
|
||||||
|
console.log('Method:', options.method)
|
||||||
|
console.log('数据:', JSON.stringify(options.data, null, 2))
|
||||||
|
|
||||||
|
const url = new URL(options.url)
|
||||||
|
const reqOptions = {
|
||||||
|
hostname: url.hostname,
|
||||||
|
port: 443,
|
||||||
|
path: url.pathname + url.search,
|
||||||
|
method: options.method || 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const req = https.request(reqOptions, (res) => {
|
||||||
|
let data = ''
|
||||||
|
res.on('data', (chunk) => { data += chunk })
|
||||||
|
res.on('end', () => {
|
||||||
|
console.log('\n📥 响应状态:', res.statusCode)
|
||||||
|
console.log('响应内容:', data)
|
||||||
|
if (options.success) {
|
||||||
|
options.success({
|
||||||
|
statusCode: res.statusCode,
|
||||||
|
data: JSON.parse(data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
req.on('error', (e) => {
|
||||||
|
console.error('❌ 请求错误:', e.message)
|
||||||
|
if (options.fail) {
|
||||||
|
options.fail(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
req.write(JSON.stringify(options.data))
|
||||||
|
req.end()
|
||||||
|
|
||||||
|
return { abort: () => req.destroy() }
|
||||||
|
},
|
||||||
|
|
||||||
|
onError: (callback) => { global._uniOnErrorCallback = callback },
|
||||||
|
onPageNotFound: (callback) => { global._uniOnPageNotFoundCallback = callback },
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟 getCurrentPages
|
||||||
|
global.getCurrentPages = () => [
|
||||||
|
{
|
||||||
|
route: 'pages/test/test',
|
||||||
|
$page: { fullPath: '/pages/test/test?id=webhook-test' }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// 模拟 window 环境
|
||||||
|
global.window = {
|
||||||
|
location: { href: 'http://localhost:8080/webhook-test' },
|
||||||
|
onerror: null,
|
||||||
|
addEventListener: () => {},
|
||||||
|
}
|
||||||
|
global.navigator = { userAgent: 'Node.js Error Monitor Test' }
|
||||||
|
|
||||||
|
// 设置环境变量
|
||||||
|
process.env.MODE = 'production'
|
||||||
|
// 注意:webhookUrl 需要通过 initErrorMonitor 传入,不能通过环境变量
|
||||||
|
|
||||||
|
// 读取并修改源代码
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const sourcePath = path.join(__dirname, '../src/index.js')
|
||||||
|
let sourceCode = fs.readFileSync(sourcePath, 'utf-8')
|
||||||
|
|
||||||
|
// 替换 import.meta.env
|
||||||
|
sourceCode = sourceCode.replace(/import\.meta\.env\.MODE/g, 'process.env.MODE || "production"')
|
||||||
|
sourceCode = sourceCode.replace(/import\.meta\.env\.VITE_WEBHOOK/g, 'process.env.VITE_WEBHOOK || ""')
|
||||||
|
|
||||||
|
const tempModulePath = path.join(__dirname, 'temp-webhook-index.js')
|
||||||
|
fs.writeFileSync(tempModulePath, sourceCode)
|
||||||
|
|
||||||
|
// 导入模块
|
||||||
|
const errorMonitor = require('./temp-webhook-index.js')
|
||||||
|
const { initErrorMonitor, reportError, getErrorStats, resetErrorStats, setErrorLevel, clearErrorCache, ERROR_LEVEL } = errorMonitor
|
||||||
|
|
||||||
|
// 延迟函数
|
||||||
|
function delay(ms) {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, ms))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主测试函数
|
||||||
|
async function runWebhookTest() {
|
||||||
|
console.log('\n========================================')
|
||||||
|
console.log(' 错误监控 Webhook 真实发送测试')
|
||||||
|
console.log('========================================\n')
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
resetErrorStats()
|
||||||
|
clearErrorCache()
|
||||||
|
initErrorMonitor({
|
||||||
|
webhookUrl: TEST_WEBHOOK,
|
||||||
|
forceEnable: true,
|
||||||
|
errorLevel: ERROR_LEVEL.STRICT,
|
||||||
|
})
|
||||||
|
console.log('✅ 错误监控已初始化')
|
||||||
|
console.log('📍 Webhook:', TEST_WEBHOOK)
|
||||||
|
await delay(500)
|
||||||
|
|
||||||
|
// 测试1: 发送手动错误
|
||||||
|
console.log('\n----------------------------------------')
|
||||||
|
console.log('🧪 测试1: 发送手动错误')
|
||||||
|
console.log('----------------------------------------')
|
||||||
|
reportError('manual', new Error('这是一条测试错误消息 - 手动上报'), {
|
||||||
|
testId: 'test-001',
|
||||||
|
testTime: new Date().toISOString(),
|
||||||
|
description: '用于验证 webhook 发送功能'
|
||||||
|
})
|
||||||
|
await delay(2000)
|
||||||
|
|
||||||
|
// 测试2: 发送 API 错误
|
||||||
|
console.log('\n----------------------------------------')
|
||||||
|
console.log('🧪 测试2: 发送 API 错误')
|
||||||
|
console.log('----------------------------------------')
|
||||||
|
clearErrorCache()
|
||||||
|
reportError('api', {
|
||||||
|
config: {
|
||||||
|
url: 'https://api.example.com/test-api',
|
||||||
|
method: 'POST',
|
||||||
|
data: { userId: 123 },
|
||||||
|
header: { 'Authorization': 'Bearer xxx' },
|
||||||
|
startTime: Date.now() - 500,
|
||||||
|
},
|
||||||
|
statusCode: 500,
|
||||||
|
data: {
|
||||||
|
code: 500,
|
||||||
|
msg: '服务器内部错误',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await delay(2000)
|
||||||
|
|
||||||
|
// 测试3: 发送网络错误
|
||||||
|
console.log('\n----------------------------------------')
|
||||||
|
console.log('🧪 测试3: 发送网络错误')
|
||||||
|
console.log('----------------------------------------')
|
||||||
|
clearErrorCache()
|
||||||
|
reportError('network', new Error('网络连接超时'), {
|
||||||
|
url: 'https://api.example.com/timeout',
|
||||||
|
method: 'GET',
|
||||||
|
retryCount: 3,
|
||||||
|
networkType: 'wifi',
|
||||||
|
})
|
||||||
|
await delay(2000)
|
||||||
|
|
||||||
|
// 清理
|
||||||
|
console.log('\n----------------------------------------')
|
||||||
|
console.log('📊 测试统计')
|
||||||
|
console.log('----------------------------------------')
|
||||||
|
const stats = getErrorStats()
|
||||||
|
console.log('总错误数:', stats.total)
|
||||||
|
console.log('手动错误:', stats.manual)
|
||||||
|
console.log('API错误:', stats.api)
|
||||||
|
console.log('网络错误:', stats.network)
|
||||||
|
|
||||||
|
// 清理临时文件
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(tempModulePath)
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
console.log('\n========================================')
|
||||||
|
console.log(' 测试完成!请检查企业微信机器人')
|
||||||
|
console.log('========================================\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
runWebhookTest().catch(console.error)
|
||||||
Reference in New Issue
Block a user