umijs / umi-request

A request tool based on fetch.
2.2k stars 336 forks source link

如何用errorHandler处理业务错误码 #257

Open GitKou opened 3 years ago

GitKou commented 3 years ago

我在responseInterceptors中抛出code!==200的错误,但是在errorhandler打印出response为null, 希望能在errorhandler中区分出http status!==200 和 业务错误码code!=='200'的两种错误, 我现在可以通过error.message这样区分,请问怎么才能区分毕竟合理? image

image

request.interceptors.response.use(errorInterceptors);

GitKou commented 3 years ago

我的问题和这个issue里的类似,https://github.com/umijs/umi-request/issues/18 评论中说用拦截器去抛出异常处理,但是在errorHandler中拿到的response是null,那么就无法根据code,做出相应的文案错误提示

GitKou commented 3 years ago

最后这么处理的,不知道有没有更标准的写法 image

GitKou commented 3 years ago

结合了https://github.com/blueju/umi-request-practice 这个库,整理了下,最终如下

/** request.ts**/
/** Request 网络请求工具 更详细的 api 文档: https://github.com/umijs/umi-request */
import { notification } from 'antd';
import { extend } from 'umi-request';

import store from 'store';
import type {
  RequestInterceptor,
  RequestOptionsInit,
  ResponseError,
  ResponseInterceptor,
} from 'umi-request';
import type { AjaxData } from '@/common';
import { HttpError, SystemError } from './error-type';

/** 异常处理程序 */
const errorHandler = (error: ResponseError) => {
  // 网络异常
  if (error.message === 'Failed to fetch') {
    notification.error({
      message: '网络异常',
      description: `${error.message}:${error?.request?.url}`,
    });
    // 阻断执行,并将错误信息传递下去
    return Promise.reject(error);
  }

  // HTTP 错误
  if (error.name === 'HttpError') {
    notification.error({
      message: 'HTTP 错误',
      description: error.message,
    });
    return Promise.reject(error);
  }

  // 系统错误
  if (error.name === 'SystemError') {
    notification.error({
      message: '系统错误',
      description: error.message,
    });
    return Promise.reject(error);
  }

  // 前置错误
  if (error.name === 'PremiseError') {
    notification.error({
      message: '前置错误',
      description: error.message,
    });
    return Promise.reject(error);
  }

  notification.error({
    message: '其他错误',
    description: error.message,
  });
  return Promise.reject(error);
};

const authHeaderInterceptor: RequestInterceptor = (url: string, options: RequestOptionsInit) => {
  const token = store.get('token');
  const { headers, ...rest } = options;

  return {
    url,
    options: {
      ...rest,
      headers: {
        ...headers,
        'access-token': token,
      },
    },
  };
};
const errorInterceptors: ResponseInterceptor = async (response) => {
  if (response.status === 200) {
    return response
      .clone()
      .json()
      .then((responseJson: AjaxData<any>) => {
        const code = responseJson?.code;
        if (code === '200') {
          return response;
        }

        throw new SystemError(`${code} ${responseJson.message} ${response.url}`, code);
      });
  }
  throw new HttpError(`${response.status} ${response.statusText} ${response.url}`);
};

/** 配置request请求时的默认参数 */
const request = extend({
  responseType: 'json',
  errorHandler, // 默认错误处理
  credentials: 'include', // 默认请求是否带上cookie
});

request.interceptors.request.use(authHeaderInterceptor);
request.interceptors.response.use(errorInterceptors);

export default request;
/** error-type.ts */
/* eslint-disable max-classes-per-file */
/**
 * HTTP 错误,除网络错误、http 状态码为 200 以外的错误
 */
export class HttpError extends Error {
  constructor(message: string) {
    super(message);
    this.name = this.constructor.name;
  }
}

/**
 * 系统错误,http 状态码为 200,但响应数据中 res.code !== '200'的错误
 */
export class SystemError extends Error {
  code: string
  constructor(message: string, code: string) {
    super(message);
    this.name = this.constructor.name;
    this.code = code;
  }
}

/**
 * Premise Error
 * 前提错误
 * 如:全局常量不存在,用户信息不存在,Token 不存在等
 */
export class PremiseError extends Error {
  constructor(message: string) {
    super(message);
    this.name = this.constructor.name;
  }
}
GitKou commented 3 years ago

自问自答可还行 ,最新一次close是五月份了:(

chenglianjie commented 2 years ago

还是给了我一些参考 感谢

is-tongben commented 2 months ago

自问自答可还行 ,最新一次close是五月份了:(

给你点个赞 👻