expo-duooomi-app/lib/fetch-logger.ts

102 lines
2.8 KiB
TypeScript

import { router } from 'expo-router'
import { storage } from './storage'
interface FetchLoggerOptions {
enableLogging?: boolean
logRequest?: boolean
logResponse?: boolean
logError?: boolean
}
const defaultOptions: FetchLoggerOptions = {
enableLogging: __DEV__,
logRequest: true,
logResponse: true,
logError: true,
}
const originalFetch = global.fetch
export const createFetchWithLogger = (options: FetchLoggerOptions = {}) => {
const config = { ...defaultOptions, ...options }
return async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
const startTime = Date.now()
const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url
const method = init?.method || 'GET'
try {
const token = await storage.getItem('token')
if (token) {
init = {
...init,
headers: {
...init?.headers,
authorization: `Bearer ${token}`,
},
}
}
const response = await originalFetch(input, init)
if (response.status === 401) {
console.warn('🔐 401 未授权,跳转到登录页')
// router.replace('/auth')
router.push('/auth')
}
return response
} catch (error) {
const duration = Date.now() - startTime
if (config.enableLogging && config.logError) {
console.group(`❌ [FETCH 错误] ${method} ${url}`)
console.error('📍 URL:', url)
console.error('🔧 Method:', method)
console.error('⏱️ Duration:', `${duration}ms`)
if (init?.headers) {
console.error('📋 Request Headers:', JSON.stringify(init.headers, null, 2))
}
if (init?.body) {
try {
const bodyContent = typeof init.body === 'string' ? init.body : JSON.stringify(init.body)
console.error('📦 Request Body:', bodyContent)
} catch (e) {
console.error('📦 Request Body: [无法序列化]')
}
}
console.error('💥 Error Type:', error?.constructor?.name || 'Unknown')
console.error('💥 Error Message:', error instanceof Error ? error.message : String(error))
if (error instanceof Error && error.stack) {
console.error('📚 Stack Trace:', error.stack)
}
if (error && typeof error === 'object') {
console.error('🔍 Error Details:', JSON.stringify(error, Object.getOwnPropertyNames(error), 2))
}
console.groupEnd()
}
throw error
}
}
}
export const fetchWithLogger = createFetchWithLogger()
export const setupGlobalFetchLogger = (options?: FetchLoggerOptions) => {
const loggedFetch = createFetchWithLogger(options)
global.fetch = loggedFetch as typeof fetch
return () => {
global.fetch = originalFetch
}
}