Android Retrofit+RxJava如何获取非200状态码的响应?
解决Retrofit处理非200状态码时的异常问题
首先,我得先理清你遇到的核心问题:你期望接口返回HTTP 200状态码,同时响应体里的code为205、msg为"successfully update",但当服务器返回201、202这类非200的2xx状态码时,你的代码触发了异常回调。
问题根源分析
你的代码里用了Observable<Response<UserUpdateResponse>>,理论上Retrofit会把所有HTTP状态码的响应都交给onSuccessUpdate处理,而不是onErr——除非你遇到了以下情况:
- 接口定义错误:如果你的
ApiService没有用Response<T>包裹返回值,而是直接返回Observable<UserUpdateResponse>,那Retrofit会默认把非200-299的状态码当成错误,触发onErr。 - 混淆了HTTP状态码和业务code:服务器返回的HTTP状态码是201/202,但响应体里的业务
code不是你预期的205,导致后续逻辑报错。 - 自定义拦截器/转换器干扰:你的Retrofit配置了自定义拦截器或转换器,强行把非200的状态码抛出异常。
针对性解决方案
1. 修正接口定义(最关键)
确保你的ApiService接口返回Observable<Response<UserUpdateResponse>>,这样就能捕获所有HTTP状态码的响应,避免直接进入错误回调:
public interface ApiService { @PUT("user/update") // 替换成你的实际接口路径 Observable<Response<UserUpdateResponse>> updateUser( @HeaderMap Map<String, String> headers, @Body UserUpdateRequest object ); }
2. 在成功回调里同时处理HTTP状态码和业务code
修改onSuccessUpdate方法,分别校验HTTP状态码和业务返回的code,覆盖所有场景:
private void onSuccessUpdate(Response<UserUpdateResponse> response) { // 先判断HTTP请求是否成功(2xx状态码) if (response.isSuccessful()) { UserUpdateResponse body = response.body(); if (body != null) { // 再校验业务code是否符合预期 if ("205".equals(body.getCode())) { // 处理正常更新成功的逻辑 Toast.makeText(this, body.getMsg(), Toast.LENGTH_SHORT).show(); hideDialogLoading(); } else { // 业务code不符合预期,处理业务错误 Toast.makeText(this, "业务错误:" + body.getMsg(), Toast.LENGTH_SHORT).show(); hideDialogLoading(); } } else { // 响应体为空,触发错误处理 onErr(new NullPointerException("响应体为空")); } } else { // HTTP状态码非2xx(包括201、202),解析错误信息 try { String errorContent = response.errorBody().string(); // 可以根据不同的HTTP状态码做针对性处理 switch (response.code()) { case 201: Toast.makeText(this, "资源创建成功,但更新状态需确认", Toast.LENGTH_SHORT).show(); break; case 202: Toast.makeText(this, "更新请求已接受,正在处理中", Toast.LENGTH_SHORT).show(); break; default: Toast.makeText(this, "HTTP错误:" + response.code(), Toast.LENGTH_SHORT).show(); } hideDialogLoading(); } catch (IOException e) { e.printStackTrace(); onErr(e); } } }
3. (可选)统一处理特定状态码(不推荐但应急可用)
如果服务器返回201/202是预期行为,但你不想在回调里单独处理,可以通过OkHttp拦截器修改状态码,让Retrofit认为是成功:
OkHttpClient okHttpClient = new OkHttpClient.Builder() .addInterceptor(chain -> { Response originalResp = chain.proceed(chain.request()); // 将201、202状态码替换为200 if (originalResp.code() == 201 || originalResp.code() == 202) { return originalResp.newBuilder() .code(200) .build(); } return originalResp; }) .build(); // 用这个client初始化Retrofit Retrofit retrofit = new Retrofit.Builder() .baseUrl("你的基础URL") .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build();
⚠️ 注意:这种方法会掩盖HTTP状态码的真实语义,201表示资源创建、202表示请求待处理,强行修改可能隐藏潜在问题,仅在特殊场景下使用。
内容的提问来源于stack exchange,提问作者Junior Frogie
相关产品推荐
相关产品推荐

