Skip to content
Latestv1.0.63

Interceptors

@yh-ui/request provides a powerful interceptor system supporting hooks before/after requests and responses, along with built-in debug, progress, and security interceptors.

Basic Interceptors

Request Interceptors

Modify configuration or add common logic before sending a request.

typescript
import { request } from '@yh-ui/request'

// Add request interceptor
request.interceptors.request.use(
  (config) => {
    // Add auth token
    const token = localStorage.getItem('token')
    if (token) {
      config.headers = {
        ...config.headers,
        Authorization: `Bearer ${token}`
      }
    }

    // Add timestamp to prevent caching
    config.params = {
      ...config.params,
      _t: Date.now()
    }

    return config
  },
  (error) => {
    // Request error handling
    return Promise.reject(error)
  }
)

Response Interceptors

Process response data before it reaches your code.

typescript
// Add response interceptor
request.interceptors.response.use(
  (response) => {
    // Handle business error codes
    if (response.data.code !== 200) {
      return Promise.reject(new Error(response.data.message))
    }
    return response
  },
  (error) => {
    // Unified error handling
    if (error.response?.status === 401) {
      // Redirect to login
      window.location.href = '/login'
    }
    return Promise.reject(error)
  }
)

Remove Interceptors

Use eject to remove added interceptors.

typescript
// Adding interceptor returns an ID
const requestId = request.interceptors.request.use((config) => {
  config.headers['X-Request-Time'] = new Date().toISOString()
  return config
})

// Remove specific interceptor
request.interceptors.request.eject(requestId)

// Clear all interceptors
request.interceptors.request.clear()

Built-in Interceptors

Debug Interceptor

Monitor all requests in development.

typescript
import { createDebugInterceptor } from '@yh-ui/request'

const debugInterceptor = createDebugInterceptor({
  enabled: import.meta.env.DEV,
  level: 'log',
  logRequestBody: true,
  logResponseBody: true
})

request.interceptors.request.use(debugInterceptor.onRequest)
request.interceptors.response.use(debugInterceptor.onResponse)

Debug Output Example:

[YH-Request] GET req_1234567890_1 → GET /api/users
[YH-Request] GET req_1234567890_1 [200] (145ms)

Sanitization:

typescript
const debugInterceptor = createDebugInterceptor({
  enabled: true,
  sanitize: (info) => {
    // Remove sensitive information
    const sanitized = { ...info }
    if (sanitized.headers?.Authorization) {
      sanitized.headers.Authorization = '***'
    }
    if (sanitized.data?.password) {
      sanitized.data.password = '***'
    }
    return sanitized
  }
})

Using DebugLogger Class:

typescript
import { DebugLogger } from '@yh-ui/request'

const logger = new DebugLogger()

// Add interceptor to collect logs
request.interceptors.response.use((response) => {
  logger.addLog({
    requestId: response.requestId,
    url: response.config.url || '',
    method: response.config.method || 'GET',
    status: response.response.status,
    duration: response.duration,
    timestamp: Date.now()
  })
  return response
})

// Get all logs
const logs = logger.getLogs()

// Clear logs
logger.clear()

Progress Interceptor

Track upload/download progress.

typescript
import { createProgressInterceptor } from '@yh-ui/request'

const progressInterceptor = createProgressInterceptor({
  onUploadProgress: (event) => {
    console.log(`Upload progress: ${event.percent.toFixed(1)}%`)
    console.log(`Uploaded: ${event.loaded}/${event.total} bytes`)
    console.log(`Rate: ${(event.rate || 0).toFixed(0)} bytes/s`)
    console.log(`ETA: ${((event.estimated || 0) / 1000).toFixed(1)}s`)
  },
  onDownloadProgress: (event) => {
    console.log(`Download progress: ${event.percent.toFixed(1)}%`)
    console.log(`Downloaded: ${event.loaded}/${event.total} bytes`)
  }
})

request.interceptors.request.use(progressInterceptor.onRequest)

ProgressEvent Structure:

typescript
interface ProgressEvent {
  loaded: number // Bytes transferred
  total: number // Total bytes
  percent: number // Progress percentage (0-100)
  rate?: number // Transfer rate (bytes/s)
  estimated?: number // Estimated remaining time (ms)
}

Upload with FormData:

typescript
const formData = new FormData()
formData.append('file', fileInput.files[0])

request.post('/api/upload', formData, {
  headers: {
    'Content-Type': 'multipart/form-data'
  }
})

Security Interceptor

CSRF protection and token refresh.

typescript
import { createSecurityInterceptor } from '@yh-ui/request'

const securityInterceptor = createSecurityInterceptor({
  csrf: {
    cookieName: 'XSRF-TOKEN',
    headerName: 'X-XSRF-TOKEN'
  },
  tokenRefresh: {
    statusCode: 401,
    refreshToken: async () => {
      const res = await fetch('/api/refresh-token', { credentials: 'include' })
      return res.ok
    },
    updateHeaders: (headers) => {
      headers['Authorization'] = `Bearer ${getNewToken()}`
    }
  }
})

request.interceptors.request.use(securityInterceptor.onRequest)

Interceptor Combination

Multiple interceptors can be used together and are executed in the order they are added.

typescript
import { createDebugInterceptor } from '@yh-ui/request'
import { createProgressInterceptor } from '@yh-ui/request'
import { createSecurityInterceptor } from '@yh-ui/request'

// Create each interceptor
const debugInterceptor = createDebugInterceptor({ enabled: true })
const progressInterceptor = createProgressInterceptor({
  onDownloadProgress: (e) => updateProgress(e.percent)
})
const securityInterceptor = createSecurityInterceptor({ csrf: {} })

// Request interceptor execution order: order added
request.interceptors.request.use(securityInterceptor.onRequest)
request.interceptors.request.use(debugInterceptor.onRequest)

// Response interceptor execution order: LIFO (last in, first out)
request.interceptors.response.use(progressInterceptor.onResponse)
request.interceptors.response.use(debugInterceptor.onResponse)

Interceptor Execution Order

Request Flow:
1. Request Interceptors (registered first → last)

2. Adapter (fetch/XHR)

3. Response Interceptors (registered last → first)

Best Practices

  • Use request interceptors for: authentication, logging, parameter normalization
  • Use response interceptors for: error handling, data transformation, token refresh
  • Keep interceptors focused and single-purpose
  • Remove interceptors when no longer needed to prevent memory leaks

Interactive Interceptors Demo

Using the interactive panel below, you can toggle different request and response interceptors, mock requests, and examine how request configurations (Headers, Params) and response data are modified and passed along the interceptor chain.

Interceptor Lifecycle Visualizer

Next Steps

Released under the MIT License.