Dio拦截器onError抛自定义异常无法捕获、执行卡住问题
问题场景
使用Dio网络框架时,在拦截器的onError回调中编写逻辑,希望针对不同错误场景抛出自定义异常,对应onError实现代码如下:
@override Future<void> onError(DioError err, ErrorInterceptorHandler handler) async { switch (err.type) { case DioErrorType.connectTimeout: case DioErrorType.sendTimeout: case DioErrorType.receiveTimeout: throw DeadlineExceededException(err.requestOptions); case DioErrorType.response: switch (err.response?.statusCode) { case 400: throw BadRequestException(err.requestOptions); case 401: throw UnauthorizedException(err.requestOptions); case 404: throw NotFoundException(err.requestOptions); case 409: throw ConflictException(err.requestOptions); case 500: throw InternalServerErrorException(err.requestOptions); } break; case DioErrorType.cancel: break; case DioErrorType.other: throw NoInternetConnectionException(err.requestOptions); } // super.onError(err, handler); return handler.next(err); }
异常现象
实际运行时,程序执行到拦截器抛出自定义异常的步骤就卡住,外层请求方法的try/catch块无法捕获到对应异常。业务侧请求方法代码如下:
static requestMyJobs() async { try { print('---------job calling api---------'); var response = await ApiBase.dio.get(ApiLinks.getMyJobsLink); print('Status code ${response.statusCode}'); var jocodedData = response.data['data']; return jocodedData.map<MyJobs>((json) => MyJobs.fromJson(json)).toList(); } on UnauthorizedException catch (f) { print("-Exception----------------"); } }
requestMyJobs方法中已经添加了UnauthorizedException的捕获逻辑,期望捕获接口返回401状态码时抛出的未授权异常,但始终无法进入捕获分支,程序无响应。
问题原因
- Dio拦截器的错误流转不支持直接在
onError回调中通过throw向外层抛自定义异常,拦截器的错误、响应、请求传递完全依赖handler对象的对应方法控制,直接throw的异常会被拦截器内部的调度逻辑吞掉,不会传递到外层调用方。 - 代码逻辑存在冲突:匹配到错误分支执行
throw后,末尾的handler.next(err)仍会将原始的DioError继续向拦截器链下游传递,异常流转逻辑混乱,最终导致程序卡住。 - 注释掉了
super.onError(err, handler)的默认实现,部分未匹配到分支的错误没有正确的流转出口。
解决方案
- 所有需要向外层传递的自定义异常,不要直接
throw,而是通过handler.reject(自定义异常)方法传递,该方法会将异常沿着Dio的调用链正常抛出,能被外层try/catch捕获。 - 每个错误分支处理完成后直接返回,不要在分支处理完后再统一调用
handler.next(err),避免错误重复传递。 - 未匹配到自定义处理逻辑的错误分支,正常调用父类
onError方法或执行handler.next(err)交给后续逻辑处理。
修正后的拦截器onError代码示例:
@override Future<void> onError(DioError err, ErrorInterceptorHandler handler) async { switch (err.type) { case DioErrorType.connectTimeout: case DioErrorType.sendTimeout: case DioErrorType.receiveTimeout: // 用reject传递自定义异常 return handler.reject(DeadlineExceededException(err.requestOptions)); case DioErrorType.response: switch (err.response?.statusCode) { case 400: return handler.reject(BadRequestException(err.requestOptions)); case 401: return handler.reject(UnauthorizedException(err.requestOptions)); case 404: return handler.reject(NotFoundException(err.requestOptions)); case 409: return handler.reject(ConflictException(err.requestOptions)); case 500: return handler.reject(InternalServerErrorException(err.requestOptions)); } // 未匹配到状态码的响应错误,继续向下传递 break; case DioErrorType.cancel: break; case DioErrorType.other: return handler.reject(NoInternetConnectionException(err.requestOptions)); } // 不需要特殊处理的错误,调用父类逻辑+传递给下游 super.onError(err, handler); return handler.next(err); }
注意:自定义异常类建议继承
DioError,可以兼容Dio内部所有错误处理逻辑,避免出现类型不兼容问题。
内容的提问来源于stack exchange,提问作者mudassar maqbool
相关产品推荐
相关产品推荐

