feat: 添加 WebSocket 和 HTTP 请求的日志上传功能
引入 uploadMiniLog 工具函数,用于将非心跳 WebSocket 消息以及 HTTP 请求的响应和错误信息上传至日志服务器。这有助于后续的监控和问题排查。
| | |
| | | getStorage, |
| | | objectSort, |
| | | } from '../utils/tools'; |
| | | import { _XP_SECRET, _UID } from '../constants/api'; |
| | | import { _ROBOTAXI_HOST, _XP_SECRET, _UID } from '../constants/api'; |
| | | import { jumpTo } from './jump'; |
| | | |
| | | const CODE_SUCCESS = 200 |
| | | const MINI_LOG_UPLOAD_PATH = '/operation/base/v1/mini-program/miniLog/uploadLog'; |
| | | const CODE_AUTH_EXPIRED_ARRAY = [12010301, 12010302, 12010303, 12010304, 12010305, 12010306, 12010320, 12010002]; |
| | | // 12010301, "登录状态已过期,请重新登录", "otp缓存已过期"), |
| | | // 12010302, "登录状态已过期,请重新登录", "otp已过期"), |
| | |
| | | header |
| | | }) |
| | | .then(async (res) => { |
| | | if (!isMiniLogUploadUrl(url)) { |
| | | uploadMiniLog( |
| | | JSON.stringify({ |
| | | type: 'http_response', |
| | | url, |
| | | request: payload, |
| | | response: res?.data, |
| | | timestamp: Date.now() |
| | | }) |
| | | ); |
| | | } |
| | | // res为包含cookies、header的经过小程序封装的数据 |
| | | // 第一层data为接口返回数据,包含接口状态码 |
| | | // 第二层data一般为业务数据 |
| | |
| | | return data |
| | | }) |
| | | .catch((err) => { |
| | | if (!isMiniLogUploadUrl(url)) { |
| | | uploadMiniLog( |
| | | JSON.stringify({ |
| | | type: 'http_error', |
| | | url, |
| | | request: payload, |
| | | response: err, |
| | | timestamp: Date.now() |
| | | }) |
| | | ); |
| | | } |
| | | console.log('request err:', url); |
| | | console.log(err); |
| | | |
| | |
| | | }); |
| | | } |
| | | |
| | | const isMiniLogUploadUrl = (url: string = '') => { |
| | | return typeof url === 'string' && url.includes(MINI_LOG_UPLOAD_PATH); |
| | | }; |
| | | |
| | | export const uploadMiniLog = async (logContent: string) => { |
| | | if (!logContent) return; |
| | | try { |
| | | const header = await buildHeader({ method: 'POST', payload: logContent }, false); |
| | | if (!header) return; |
| | | const uploadUrl = `${_ROBOTAXI_HOST}${MINI_LOG_UPLOAD_PATH}`; |
| | | Taro.request({ |
| | | url: uploadUrl, |
| | | method: 'POST', |
| | | data: logContent, |
| | | header: { |
| | | ...header, |
| | | 'Content-Type': 'application/json' |
| | | } |
| | | }).catch(() => { }); |
| | | } catch (_) { } |
| | | }; |
| | | |
| | | async function buildHeader(options, needLogin) { |
| | | const { method = 'POST', payload, extraHeader = {} } = options; |
| | | const header = Object.assign({}, PUBLIC_HEADER); |
| | |
| | | import { getStorage } from './tools'; |
| | | import { _UID } from '../constants/api'; |
| | | import { safeParse } from './Robotaxi-public-method'; |
| | | import { uploadMiniLog } from './request'; |
| | | |
| | | type MessageCallback = (data: any) => void; |
| | | |
| | |
| | | private heartbeatTimeout: number = 3000; // 5秒收不到响应即视为掉线 |
| | | private listeners: Map<string, MessageCallback[]> = new Map(); |
| | | private globalEventsBound: boolean = false; |
| | | |
| | | private isHeartbeatMessage(data: any) { |
| | | const type = String(data?.type || '').toLowerCase(); |
| | | return type === 'ping' || type === 'pong'; |
| | | } |
| | | |
| | | private constructor() { } |
| | | |
| | |
| | | try { |
| | | data = safeParse(res.data as string, {}); |
| | | console.log('收到 WebSocket 消息:', res.data); |
| | | if (!this.isHeartbeatMessage(data)) { |
| | | const messageContent = typeof res.data === 'string' ? res.data : JSON.stringify(res.data); |
| | | uploadMiniLog(messageContent); |
| | | } |
| | | } catch (e) { |
| | | console.warn('解析 WebSocket data 失败:', res.data); |
| | | this.notifyListeners('message', res.data); |
| | |
| | | try { |
| | | data = safeParse(res.data as string, {}); |
| | | console.log('收到 WebSocket 消息:', res.data); |
| | | if (!this.isHeartbeatMessage(data)) { |
| | | const messageContent = typeof res.data === 'string' ? res.data : JSON.stringify(res.data); |
| | | uploadMiniLog(messageContent); |
| | | } |
| | | } catch (e) { |
| | | console.warn('解析 WebSocket data 失败:', res.data); |
| | | this.notifyListeners('message', res.data); |