422 lines
12 KiB
JavaScript
422 lines
12 KiB
JavaScript
/**
|
||
* 移动端HTTP调试工具
|
||
* 专门用于调试uni-app在移动设备上的HTTP请求问题
|
||
*/
|
||
|
||
/**
|
||
* 详细的HTTP请求调试
|
||
*/
|
||
export async function debugHTTPRequest(url, options = {}) {
|
||
console.log('🔧 开始HTTP请求调试...')
|
||
console.log('=' * 60)
|
||
|
||
const debugInfo = {
|
||
url,
|
||
options,
|
||
environment: {},
|
||
networkInfo: {},
|
||
requestDetails: {},
|
||
response: null,
|
||
error: null,
|
||
recommendations: []
|
||
}
|
||
|
||
try {
|
||
// 1. 收集环境信息
|
||
console.log('📱 收集环境信息...')
|
||
debugInfo.environment = await collectEnvironmentInfo()
|
||
|
||
// 2. 检查网络状态
|
||
console.log('📶 检查网络状态...')
|
||
debugInfo.networkInfo = await collectNetworkInfo()
|
||
|
||
// 3. 分析请求配置
|
||
console.log('⚙️ 分析请求配置...')
|
||
debugInfo.requestDetails = analyzeRequestConfig(url, options)
|
||
|
||
// 4. 执行HTTP请求
|
||
console.log('🌐 执行HTTP请求...')
|
||
const result = await executeDebugRequest(url, options)
|
||
|
||
if (result.success) {
|
||
debugInfo.response = result.response
|
||
console.log('✅ HTTP请求成功')
|
||
} else {
|
||
debugInfo.error = result.error
|
||
console.log('❌ HTTP请求失败')
|
||
}
|
||
|
||
// 5. 生成诊断建议
|
||
debugInfo.recommendations = generateRecommendations(debugInfo)
|
||
|
||
} catch (error) {
|
||
console.error('❌ HTTP调试异常:', error)
|
||
debugInfo.error = error
|
||
}
|
||
|
||
// 输出调试报告
|
||
printDebugReport(debugInfo)
|
||
|
||
return debugInfo
|
||
}
|
||
|
||
/**
|
||
* 收集环境信息
|
||
*/
|
||
async function collectEnvironmentInfo() {
|
||
const env = {}
|
||
|
||
try {
|
||
// 系统信息
|
||
const systemInfo = uni.getSystemInfoSync()
|
||
env.platform = systemInfo.platform
|
||
env.system = systemInfo.system
|
||
env.version = systemInfo.version
|
||
env.SDKVersion = systemInfo.SDKVersion
|
||
env.brand = systemInfo.brand
|
||
env.model = systemInfo.model
|
||
|
||
console.log(`📱 设备: ${env.brand} ${env.model}`)
|
||
console.log(`💻 系统: ${env.system}`)
|
||
console.log(`🔢 版本: ${env.version}`)
|
||
|
||
} catch (error) {
|
||
console.log('⚠️ 无法获取系统信息:', error)
|
||
}
|
||
|
||
return env
|
||
}
|
||
|
||
/**
|
||
* 收集网络信息
|
||
*/
|
||
async function collectNetworkInfo() {
|
||
const network = {}
|
||
|
||
try {
|
||
// 网络类型
|
||
const networkType = await uni.getNetworkType()
|
||
network.type = networkType.networkType
|
||
network.isConnected = networkType.isConnected
|
||
|
||
console.log(`📶 网络类型: ${network.type}`)
|
||
console.log(`🔗 连接状态: ${network.isConnected ? '已连接' : '未连接'}`)
|
||
|
||
// 如果uni.getNetworkType()返回未连接,但类型是wifi,可能是API问题
|
||
if (network.type === 'wifi' && !network.isConnected) {
|
||
console.log('⚠️ 网络状态检测可能不准确,WiFi类型但显示未连接')
|
||
// 尝试简单的网络测试来验证实际连接状态
|
||
try {
|
||
const testResult = await new Promise((resolve, reject) => {
|
||
uni.request({
|
||
url: 'https://www.baidu.com',
|
||
method: 'GET',
|
||
timeout: 3000,
|
||
success: () => resolve(true),
|
||
fail: () => resolve(false)
|
||
})
|
||
})
|
||
network.actuallyConnected = testResult
|
||
console.log(`🌐 实际网络连接测试: ${testResult ? '成功' : '失败'}`)
|
||
} catch (error) {
|
||
network.actuallyConnected = false
|
||
}
|
||
}
|
||
|
||
// WiFi信息(如果可用)
|
||
if (network.type === 'wifi') {
|
||
try {
|
||
const wifiInfo = await uni.getConnectedWifi()
|
||
network.wifi = {
|
||
SSID: wifiInfo.SSID,
|
||
BSSID: wifiInfo.BSSID,
|
||
secure: wifiInfo.secure,
|
||
signalStrength: wifiInfo.signalStrength
|
||
}
|
||
console.log(`📡 WiFi SSID: ${network.wifi.SSID}`)
|
||
console.log(`📶 信号强度: ${network.wifi.signalStrength}`)
|
||
} catch (error) {
|
||
console.log('⚠️ 无法获取WiFi详细信息:', error?.errMsg || error || 'Permission denied')
|
||
network.wifiError = error?.errMsg || error || 'Permission denied'
|
||
|
||
// 提供权限申请建议
|
||
console.log('💡 可能需要申请位置权限才能获取WiFi信息')
|
||
}
|
||
}
|
||
|
||
} catch (error) {
|
||
console.log('❌ 网络信息获取失败:', error)
|
||
network.error = error
|
||
}
|
||
|
||
return network
|
||
}
|
||
|
||
/**
|
||
* 分析请求配置
|
||
*/
|
||
function analyzeRequestConfig(url, options) {
|
||
const analysis = {
|
||
url,
|
||
method: options.method || 'GET',
|
||
timeout: options.timeout || 60000,
|
||
headers: options.header || {},
|
||
isLocalNetwork: false,
|
||
isHTTPS: false,
|
||
issues: []
|
||
}
|
||
|
||
// URL分析
|
||
if (url.startsWith('https://')) {
|
||
analysis.isHTTPS = true
|
||
}
|
||
|
||
// 检查是否为局域网地址
|
||
const localNetworkPatterns = [
|
||
/^https?:\/\/192\.168\./,
|
||
/^https?:\/\/10\./,
|
||
/^https?:\/\/172\.(1[6-9]|2[0-9]|3[01])\./,
|
||
/^https?:\/\/localhost/,
|
||
/^https?:\/\/127\.0\.0\.1/
|
||
]
|
||
|
||
analysis.isLocalNetwork = localNetworkPatterns.some(pattern => pattern.test(url))
|
||
|
||
// 配置问题检查
|
||
if (analysis.isLocalNetwork && analysis.isHTTPS) {
|
||
analysis.issues.push('⚠️ 局域网地址使用HTTPS可能导致证书错误')
|
||
}
|
||
|
||
if (analysis.timeout < 5000) {
|
||
analysis.issues.push('⚠️ 超时时间过短,建议设置为10秒以上')
|
||
}
|
||
|
||
if (!analysis.headers['User-Agent']) {
|
||
analysis.issues.push('💡 建议添加User-Agent头')
|
||
}
|
||
|
||
console.log(`🎯 请求URL: ${analysis.url}`)
|
||
console.log(`📋 请求方法: ${analysis.method}`)
|
||
console.log(`⏱️ 超时时间: ${analysis.timeout}ms`)
|
||
console.log(`🏠 局域网请求: ${analysis.isLocalNetwork ? '是' : '否'}`)
|
||
|
||
return analysis
|
||
}
|
||
|
||
/**
|
||
* 执行调试请求
|
||
*/
|
||
async function executeDebugRequest(url, options = {}) {
|
||
const startTime = Date.now()
|
||
|
||
// 构建完整的请求配置
|
||
const requestConfig = {
|
||
url,
|
||
method: options.method || 'GET',
|
||
timeout: options.timeout || 15000, // 延长到15秒
|
||
header: {
|
||
'Content-Type': 'application/json',
|
||
'User-Agent': 'uni-app/ESP32Client-Debug',
|
||
'Cache-Control': 'no-cache',
|
||
'Connection': 'keep-alive',
|
||
...options.header
|
||
},
|
||
sslVerify: false,
|
||
withCredentials: false,
|
||
...options
|
||
}
|
||
|
||
console.log('📋 完整请求配置:', JSON.stringify(requestConfig, null, 2))
|
||
|
||
// 重试机制:最多重试2次
|
||
for (let attempt = 1; attempt <= 2; attempt++) {
|
||
try {
|
||
console.log(`🔄 第${attempt}次尝试...`)
|
||
|
||
const response = await new Promise((resolve, reject) => {
|
||
uni.request({
|
||
...requestConfig,
|
||
success: (res) => {
|
||
const duration = Date.now() - startTime
|
||
console.log(`✅ 请求成功 (${duration}ms, 第${attempt}次尝试)`)
|
||
console.log('📄 响应状态:', res.statusCode)
|
||
console.log('📄 响应头:', res.header)
|
||
console.log('📄 响应数据:', res.data)
|
||
resolve(res)
|
||
},
|
||
fail: (err) => {
|
||
const duration = Date.now() - startTime
|
||
console.log(`❌ 请求失败 (${duration}ms, 第${attempt}次尝试)`)
|
||
console.log('❌ 错误信息:', err.errMsg)
|
||
console.log('❌ 错误码:', err.errno)
|
||
reject(err)
|
||
}
|
||
})
|
||
})
|
||
|
||
return {
|
||
success: true,
|
||
response,
|
||
duration: Date.now() - startTime,
|
||
attempts: attempt
|
||
}
|
||
|
||
} catch (error) {
|
||
if (attempt === 2) {
|
||
// 最后一次重试失败
|
||
return {
|
||
success: false,
|
||
error,
|
||
duration: Date.now() - startTime,
|
||
attempts: attempt
|
||
}
|
||
}
|
||
|
||
// 重试前等待500ms
|
||
console.log(`⏳ 等待500ms后重试...`)
|
||
await new Promise(resolve => setTimeout(resolve, 500))
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 生成诊断建议
|
||
*/
|
||
function generateRecommendations(debugInfo) {
|
||
const recommendations = []
|
||
|
||
// 网络相关建议
|
||
if (debugInfo.networkInfo.type !== 'wifi') {
|
||
recommendations.push('📶 建议连接到WiFi网络,移动网络无法访问局域网设备')
|
||
}
|
||
|
||
if (debugInfo.networkInfo.wifiError) {
|
||
recommendations.push('🔐 WiFi权限可能被限制,请检查APP的位置权限')
|
||
}
|
||
|
||
// 请求配置建议
|
||
if (debugInfo.requestDetails.issues.length > 0) {
|
||
recommendations.push(...debugInfo.requestDetails.issues)
|
||
}
|
||
|
||
// 错误相关建议
|
||
if (debugInfo.error) {
|
||
const errorMsg = debugInfo.error.errMsg || debugInfo.error.message || ''
|
||
|
||
if (errorMsg.includes('timeout')) {
|
||
recommendations.push('⏱️ 请求超时,可能原因:')
|
||
recommendations.push(' - 目标设备未启动或不可达')
|
||
recommendations.push(' - 网络延迟过高')
|
||
recommendations.push(' - 防火墙阻止连接')
|
||
}
|
||
|
||
if (errorMsg.includes('fail')) {
|
||
recommendations.push('🚫 连接失败,可能原因:')
|
||
recommendations.push(' - 设备不在同一网络')
|
||
recommendations.push(' - IP地址错误')
|
||
recommendations.push(' - 端口被占用或关闭')
|
||
}
|
||
|
||
if (errorMsg.includes('certificate') || errorMsg.includes('ssl')) {
|
||
recommendations.push('🔒 SSL/证书问题,建议使用HTTP而非HTTPS')
|
||
}
|
||
}
|
||
|
||
// Android特定建议
|
||
if (debugInfo.environment.platform === 'android') {
|
||
recommendations.push('🤖 Android特定建议:')
|
||
recommendations.push(' - 确保APP有网络权限')
|
||
recommendations.push(' - 检查是否允许明文HTTP流量')
|
||
recommendations.push(' - 尝试云打包而非真机调试')
|
||
}
|
||
|
||
return recommendations
|
||
}
|
||
|
||
/**
|
||
* 打印调试报告
|
||
*/
|
||
function printDebugReport(debugInfo) {
|
||
console.log('=' * 60)
|
||
console.log('📋 HTTP调试报告')
|
||
console.log('=' * 60)
|
||
|
||
console.log('🎯 请求信息:')
|
||
console.log(` URL: ${debugInfo.url}`)
|
||
console.log(` 方法: ${debugInfo.requestDetails?.method || 'GET'}`)
|
||
console.log(` 超时: ${debugInfo.requestDetails?.timeout || 'N/A'}ms`)
|
||
|
||
console.log('\n📱 环境信息:')
|
||
if (debugInfo.environment.platform) {
|
||
console.log(` 平台: ${debugInfo.environment.platform}`)
|
||
console.log(` 设备: ${debugInfo.environment.brand} ${debugInfo.environment.model}`)
|
||
console.log(` 系统: ${debugInfo.environment.system}`)
|
||
}
|
||
|
||
console.log('\n📶 网络信息:')
|
||
console.log(` 类型: ${debugInfo.networkInfo?.type || 'unknown'}`)
|
||
console.log(` 状态: ${debugInfo.networkInfo?.isConnected ? '已连接' : '未连接'}`)
|
||
if (debugInfo.networkInfo?.wifi?.SSID) {
|
||
console.log(` WiFi: ${debugInfo.networkInfo.wifi.SSID}`)
|
||
}
|
||
|
||
console.log('\n🎯 请求结果:')
|
||
if (debugInfo.response) {
|
||
console.log(` ✅ 成功 (状态码: ${debugInfo.response.statusCode})`)
|
||
} else if (debugInfo.error) {
|
||
console.log(` ❌ 失败 (${debugInfo.error.errMsg || debugInfo.error.message})`)
|
||
}
|
||
|
||
if (debugInfo.recommendations.length > 0) {
|
||
console.log('\n💡 诊断建议:')
|
||
debugInfo.recommendations.forEach(rec => console.log(` ${rec}`))
|
||
}
|
||
|
||
console.log('=' * 60)
|
||
}
|
||
|
||
/**
|
||
* 快速测试ESP32连接
|
||
*/
|
||
export async function quickTestESP32(ip = '192.168.1.98') {
|
||
console.log(`🚀 快速测试ESP32连接: ${ip}`)
|
||
|
||
const testAPIs = [
|
||
'/api/device/info',
|
||
'/api/status',
|
||
'/api/info',
|
||
'/'
|
||
]
|
||
|
||
for (const api of testAPIs) {
|
||
const url = `http://${ip}:80${api}`
|
||
console.log(`\n🔍 测试: ${api}`)
|
||
|
||
const result = await debugHTTPRequest(url, {
|
||
method: 'GET',
|
||
timeout: 8000
|
||
})
|
||
|
||
if (result.response && result.response.statusCode === 200) {
|
||
console.log(`✅ 找到可用接口: ${api}`)
|
||
return {
|
||
success: true,
|
||
api,
|
||
ip,
|
||
response: result.response
|
||
}
|
||
}
|
||
}
|
||
|
||
console.log('❌ 所有接口测试失败')
|
||
return {
|
||
success: false,
|
||
ip
|
||
}
|
||
}
|
||
|
||
export default {
|
||
debugHTTPRequest,
|
||
quickTestESP32
|
||
}
|