You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:14:34