跳到主要内容

错误处理

统一错误处理是中间件的核心应用场景之一。通过中间件,你可以集中处理所有请求的错误,避免在每个请求中重复编写 try/catch 逻辑。

使用 instanceof 判断错误类型

import { request, RequestException, TimeoutException } from 'keq'

try {
  await request.get('/cats').timeout(5000)
} catch (err) {
  if (err instanceof TimeoutException) {
    console.error('请求超时,请稍后重试')
  } else if (err instanceof RequestException) {
    console.error(`请求失败: ${err.statusCode} ${err.message}`)
  } else {
    console.error('未知错误:', err)
  }
}
提示

异常类的完整定义和参数说明,请参阅 API 参考 - 异常类型

在中间件中统一处理错误

import { request, KeqMiddleware, RequestException } from 'keq'

function errorHandler(): KeqMiddleware {
  return async (context, next) => {
    await next()

    if (context.response) {
      const { status, statusText } = context.response

      if (status === 401) {
        throw new RequestException(401, statusText, { fatal: true })
      } else if (status === 403) {
        throw new RequestException(403, statusText, { fatal: true })
      } else if (status === 404) {
        throw new RequestException(404, statusText, { fatal: true })
      } else if (status >= 400 && status < 500) {
        // 其他客户端错误不重试
        throw new RequestException(status, statusText, { fatal: true })
      } else if (status >= 500) {
        // 服务器错误可重试
        const message = await context.response.text()
        throw new RequestException(status, message)
      }
    }
  }
}

request.use(errorHandler())

精确捕获不同类型的错误

import { request, RequestException } from 'keq'

try {
  await request.get('/cats')
} catch (err) {
  if (err instanceof RequestException) {
    switch (err.statusCode) {
      case 401:
        console.error('未授权,请先登录')
        break
      case 403:
        console.error('没有权限访问该资源')
        break
      case 404:
        console.error('资源不存在')
        break
      default:
        console.error(`请求失败: ${err.statusCode} ${err.message}`)
    }
  }
}

使用自定义异常类

import { request, KeqMiddleware, RequestException } from 'keq'

// 自定义异常类
export class UnauthorizedException extends RequestException {
  constructor(message?: string) {
    super(401, message || 'Unauthorized', { fatal: true })
    this.name = 'UnauthorizedException'
  }
}

export class ForbiddenException extends RequestException {
  constructor(message?: string) {
    super(403, message || 'Forbidden', { fatal: true })
    this.name = 'ForbiddenException'
  }
}

function errorHandler(): KeqMiddleware {
  return async (context, next) => {
    await next()

    if (context.response) {
      const { status, statusText } = context.response

      if (status === 401) {
        throw new UnauthorizedException(statusText)
      } else if (status === 403) {
        throw new ForbiddenException(statusText)
      } else if (status >= 400) {
        throw new RequestException(status, statusText)
      }
    }
  }
}

request.use(errorHandler())

// 使用时可以精确捕获不同类型的错误
try {
  await request.get('/cats')
} catch (err) {
  if (err instanceof UnauthorizedException) {
    // 跳转到登录页
  } else if (err instanceof ForbiddenException) {
    // 显示权限不足提示
  }
}