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

如何在Spring Integration Java DSL中自定义错误响应

问题分析与解决方案

首先,你的代码出现ClassCastException的核心原因是:当目标API宕机时,Http.outboundGateway抛出的是ResourceAccessException(连接超时/拒绝连接等网络异常的包装类),但你的错误处理流强制将其转换为HttpClientErrorException,导致类型转换失败。同时,当前错误处理返回的RuntimeException会触发Spring默认错误处理器,返回通用的500错误响应。

以下是实现自定义异常响应的分步解决方案:


1. 修复类型转换异常

首先需要在错误处理流中区分不同的异常类型,避免强制转换:

步骤1:创建自定义错误响应DTO

定义一个用于返回给客户端的结构化错误响应类:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class CustomErrorResponse {
    private String timestamp;
    private int status;
    private String error;
    private String message;
    private String path;

    public CustomErrorResponse(int status, String error, String message, String path) {
        this.timestamp = LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME);
        this.status = status;
        this.error = error;
        this.message = message;
        this.path = path;
    }

    // Getter方法(用于JSON序列化)
    public String getTimestamp() { return timestamp; }
    public int getStatus() { return status; }
    public String getError() { return error; }
    public String getMessage() { return message; }
    public String getPath() { return path; }
}

步骤2:重构错误处理流

修改httpProxyErrorFlow,处理不同异常类型并返回自定义响应:

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.integration.transformer.Transformers;
import org.springframework.messaging.MessagingException;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.ResourceAccessException;

@Bean
public IntegrationFlow httpProxyErrorFlow() {
    return f -> f
            // 提取原始异常(处理MessagingException包装的情况)
            .transform(payload -> {
                if (payload instanceof MessagingException) {
                    return ((MessagingException) payload).getCause();
                }
                return payload;
            })
            // 根据异常类型生成自定义响应
            .handle((payload, headers) -> {
                // 从请求头获取原始请求路径
                String path = headers.getOrDefault(HttpHeaders.REQUEST_URL, "/narko/api/patient/by-pinpp").toString();
                CustomErrorResponse errorResponse;
                HttpStatus status;

                if (payload instanceof ResourceAccessException) {
                    // 处理目标服务宕机、连接失败等情况
                    status = HttpStatus.SERVICE_UNAVAILABLE;
                    errorResponse = new CustomErrorResponse(
                            status.value(),
                            status.getReasonPhrase(),
                            "目标服务暂时不可用,请稍后重试",
                            path
                    );
                } else if (payload instanceof HttpClientErrorException) {
                    // 处理目标服务返回的4xx错误
                    HttpClientErrorException ex = (HttpClientErrorException) payload;
                    status = ex.getStatusCode();
                    errorResponse = new CustomErrorResponse(
                            status.value(),
                            status.getReasonPhrase(),
                            "请求目标服务失败:" + ex.getMessage(),
                            path
                    );
                } else {
                    // 处理其他未知异常
                    status = HttpStatus.INTERNAL_SERVER_ERROR;
                    errorResponse = new CustomErrorResponse(
                            status.value(),
                            status.getReasonPhrase(),
                            "服务器内部错误",
                            path
                    );
                }

                // 构建包含状态码的响应消息
                return MessageBuilder.withPayload(errorResponse)
                        .setHeader(HttpHeaders.STATUS_CODE, status)
                        .build();
            })
            // 将响应对象序列化为JSON
            .transform(Transformers.toJson());
}

2. 修正其他潜在问题

  • 修正main方法中的类名错误(当前代码中类是IntegrationApp,但启动的是MinzdravApplication):
public static void main(String[] args) {
    SpringApplication.run(IntegrationApp.class, args);
}

3. 效果验证

当目标API宕机时,客户端会收到如下自定义响应:

{
   "timestamp": "2022-08-10T15:30:00.123+08:00",
   "status": 503,
   "error": "Service Unavailable",
   "message": "目标服务暂时不可用,请稍后重试",
   "path": "/narko/api/patient/by-pinpp"
}

同时日志中不会再出现ClassCastException异常。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 23:54:05