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

使用Java HttpClient(JsonBodyHandler)如何处理非200状态响应?

Java HttpClient 处理非200响应及差异化JSON反序列化

核心问题说明

Java HttpClient 默认不会像RestTemplate那样在非200状态码时自动抛出异常,而是会继续尝试用指定的BodyHandler处理响应体。当错误响应的JSON结构和成功响应的POJO不匹配时,就会触发反序列化异常。

解决方案思路

我们需要:

  • 先检查响应的状态码,区分成功/错误场景
  • 针对错误场景,用对应的错误POJO去反序列化响应体
  • 可以通过自定义BodyHandler封装逻辑,或者在获取响应后手动分支处理

具体实现步骤

1. 定义错误响应的POJO

对应服务端返回的错误结构,创建匹配的实体类:

public class ApiError {
    private ErrorDetail error;

    // getter、setter、无参构造器
    public ErrorDetail getError() { return error; }
    public void setError(ErrorDetail error) { this.error = error; }
}

public class ErrorDetail {
    private String code;
    private String message;

    // getter、setter、无参构造器
    public String getCode() { return code; }
    public void setCode(String code) { this.code = code; }
    public String getMessage() { return message; }
    public void setMessage(String message) { this.message = message; }
}

2. 自定义BodyHandler处理差异化反序列化

实现一个通用的ConditionalJsonBodyHandler,根据状态码自动选择反序列化的目标类:

import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.InputStream;
import java.net.http.HttpResponse;
import java.util.function.Supplier;

public class ConditionalJsonBodyHandler<T> implements HttpResponse.BodyHandler<Supplier<T>> {
    private final Class<T> successClass;
    private final Class<?> errorClass;
    private final ObjectMapper objectMapper = new ObjectMapper();

    public ConditionalJsonBodyHandler(Class<T> successClass, Class<?> errorClass) {
        this.successClass = successClass;
        this.errorClass = errorClass;
    }

    @Override
    public HttpResponse.BodySubscriber<Supplier<T>> apply(HttpResponse.ResponseInfo responseInfo) {
        int statusCode = responseInfo.statusCode();
        Class<?> targetClass = (statusCode >= 200 && statusCode < 300) ? successClass : errorClass;

        return HttpResponse.BodySubscribers.mapping(
                HttpResponse.BodySubscribers.ofInputStream(),
                inputStream -> () -> {
                    try (InputStream is = inputStream) {
                        return targetClass.cast(objectMapper.readValue(is, targetClass));
                    } catch (IOException e) {
                        throw new RuntimeException("Failed to deserialize response", e);
                    }
                }
        );
    }
}

3. 使用自定义Handler处理请求

修改原有请求代码,通过自定义Handler统一处理成功和错误响应:

// 创建客户端
var client = HttpClient.newHttpClient();

// 创建请求
var request = HttpRequest.newBuilder(
        URI.create("https://api.nasa.gov/planetary/apod?api_key=INCORRECT_KEY"))
        .header("accept", "application/json")
        .build();

// 发送请求,使用自定义Handler
var response = client.send(request, new ConditionalJsonBodyHandler<>(APOD.class, ApiError.class));
int statusCode = response.statusCode();

if (statusCode >= 200 && statusCode < 300) {
    APOD apod = response.body().get();
    // 处理成功逻辑
    System.out.println("成功获取APOD: " + apod.getTitle());
} else {
    ApiError apiError = (ApiError) response.body().get();
    // 处理错误逻辑
    System.out.println("请求错误: 代码=" + apiError.getError().getCode() + ", 消息=" + apiError.getError().getMessage());
}

替代方案:手动分支处理

如果不想自定义Handler,也可以先获取原始响应,再根据状态码分别处理:

var client = HttpClient.newHttpClient();
var request = HttpRequest.newBuilder(URI.create("https://api.nasa.gov/planetary/apod?api_key=INCORRECT_KEY"))
        .header("accept", "application/json")
        .build();

// 先获取带InputStream的原始响应
var rawResponse = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
int statusCode = rawResponse.statusCode();
ObjectMapper objectMapper = new ObjectMapper();

try (InputStream is = rawResponse.body()) {
    if (statusCode >= 200 && statusCode < 300) {
        APOD apod = objectMapper.readValue(is, APOD.class);
        // 成功逻辑处理
    } else {
        ApiError apiError = objectMapper.readValue(is, ApiError.class);
        // 错误逻辑处理
    }
} catch (IOException e) {
    // 处理IO或反序列化异常
}

关键说明

  • 自定义Handler的方式更贴合HttpClient的设计模式,将反序列化逻辑封装统一管理
  • 两种方案的核心都是先判断状态码,再选择对应的POJO进行反序列化
  • 需确保Jackson能正确处理POJO反序列化(如提供无参构造器、字段名与JSON键匹配等)

内容的提问来源于stack exchange,提问作者CodeBot

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 03:52:50