Spring Integration:如何通过XML/注解配置保留HTTP错误码与响应体?
没问题!我来详细说明如何用Spring XML配置和注解两种方式,实现从出站网关到入站网关的响应中保留HTTP错误码及响应体。
首先明确核心逻辑:默认情况下,Spring Integration的HTTP出站网关收到非2xx响应时会抛出HttpStatusCodeException,导致原始错误响应体和状态码丢失。我们需要通过异常处理机制,把这些错误信息提取出来,封装成正常消息传递回入站网关。
基于Spring XML配置的实现
1. 定义异常处理Advice
这个Advice会捕获出站网关抛出的HTTP异常,将异常导向专门的错误处理通道:
<bean id="httpErrorHandlingAdvice" class="org.springframework.integration.handler.advice.ExpressionEvaluatingRequestHandlerAdvice"> <!-- 指定异常发生时的处理逻辑,这里将状态码作为临时结果 --> <property name="onFailureExpression" value="T(org.springframework.http.HttpStatus).valueOf(#exception.statusCode.value())"/> <!-- 异常将被发送到这个通道进行后续处理 --> <property name="failureChannel" ref="errorHandlingChannel"/> <!-- 允许将异常处理后的结果作为正常消息返回 --> <property name="returnFailureExpressionResult" value="true"/> </bean>
2. 配置错误处理通道与处理器
创建专门的通道接收异常消息,然后自定义处理器提取错误响应体和状态码:
<!-- 错误处理通道 --> <int:channel id="errorHandlingChannel"/> <!-- 自定义错误处理器,提取错误信息并封装成响应 --> <int:service-activator input-channel="errorHandlingChannel" output-channel="replyChannel"> <bean class="com.example.HttpErrorResponseHandler"/> </int:service-activator>
对应的自定义处理器类实现:
public class HttpErrorResponseHandler { public Message<?> handleHttpError(Message<Exception> errorMessage) { Exception exception = errorMessage.getPayload(); if (exception instanceof HttpStatusCodeException) { HttpStatusCodeException httpEx = (HttpStatusCodeException) exception; // 提取原始响应体和状态码 String responseBody = httpEx.getResponseBodyAsString(); HttpStatus statusCode = httpEx.getStatusCode(); // 封装成自定义错误响应对象(你可以根据业务需求定义这个类) ErrorResponse errorResponse = new ErrorResponse(statusCode.value(), responseBody); // 构建包含错误信息的消息,同时把状态码放到Header中 return MessageBuilder.withPayload(errorResponse) .setHeader(HttpHeaders.STATUS_CODE, statusCode) .build(); } // 处理非HTTP异常的情况 return MessageBuilder.withPayload(exception).build(); } // 自定义错误响应对象示例 public static class ErrorResponse { private int statusCode; private String responseBody; // 构造方法、getter/setter省略 public ErrorResponse(int statusCode, String responseBody) { this.statusCode = statusCode; this.responseBody = responseBody; } } }
3. 配置出站网关并关联Advice
在出站网关中引用刚才定义的异常处理Advice:
<int-http:outbound-gateway id="externalServiceOutboundGateway" request-channel="requestChannel" url="http://your-external-service/api/**" http-method="POST" reply-channel="replyChannel" request-handler-advice-chain="httpErrorHandlingAdvice"/> <!-- 入站网关关联的请求通道 --> <int:channel id="requestChannel"/> <!-- 最终返回给入站网关的响应通道 --> <int:channel id="replyChannel"/>
基于Spring注解的实现
1. 配置异常处理Advice与通道
用@Bean定义Advice和错误处理通道:
@Configuration @EnableIntegration public class GatewayConfig { // 异常处理Advice @Bean public ExpressionEvaluatingRequestHandlerAdvice httpErrorHandlingAdvice() { ExpressionEvaluatingRequestHandlerAdvice advice = new ExpressionEvaluatingRequestHandlerAdvice(); advice.setOnFailureExpressionString("T(org.springframework.http.HttpStatus).valueOf(#exception.statusCode.value())"); advice.setFailureChannel(errorHandlingChannel()); advice.setReturnFailureExpressionResult(true); return advice; } // 错误处理通道 @Bean public MessageChannel errorHandlingChannel() { return new DirectChannel(); } // 自定义错误处理器 @ServiceActivator(inputChannel = "errorHandlingChannel", outputChannel = "replyChannel") public Message<?> handleHttpError(Message<Exception> errorMessage) { Exception exception = errorMessage.getPayload(); if (exception instanceof HttpStatusCodeException) { HttpStatusCodeException httpEx = (HttpStatusCodeException) exception; ErrorResponse errorResponse = new ErrorResponse(httpEx.getStatusCode().value(), httpEx.getResponseBodyAsString()); return MessageBuilder.withPayload(errorResponse) .setHeader(HttpHeaders.STATUS_CODE, httpEx.getStatusCode()) .build(); } return MessageBuilder.withPayload(exception).build(); } // 自定义错误响应对象 public static class ErrorResponse { private int statusCode; private String responseBody; public ErrorResponse(int statusCode, String responseBody) { this.statusCode = statusCode; this.responseBody = responseBody; } // getter/setter省略 } }
2. 配置HTTP出站网关
用@Bean创建出站网关实例,并关联异常处理Advice:
@Configuration public class OutboundGatewayConfig { @Bean @ServiceActivator(inputChannel = "requestChannel") public HttpRequestExecutingMessageHandler externalServiceOutboundGateway() { HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler("http://your-external-service/api/**"); handler.setHttpMethod(HttpMethod.POST); handler.setOutputChannel(replyChannel()); // 关联异常处理Advice handler.setAdviceChain(Collections.singletonList(httpErrorHandlingAdvice())); return handler; } @Bean public MessageChannel requestChannel() { return new DirectChannel(); } @Bean public MessageChannel replyChannel() { return new DirectChannel(); } // 注入之前定义的异常处理Advice @Autowired private ExpressionEvaluatingRequestHandlerAdvice httpErrorHandlingAdvice; }
3. 配置入站网关(示例)
最后,你的入站网关只需要关联requestChannel和replyChannel,就能收到包含错误码和响应体的消息了:
@MessagingGateway(defaultRequestChannel = "requestChannel", defaultReplyChannel = "replyChannel") public interface ApiGateway { ErrorResponse callExternalService(YourRequest request); }
这样配置后,当外部服务返回4xx/5xx错误时,出站网关不会抛出异常,而是将错误码和响应体封装成ErrorResponse对象,通过replyChannel传递回入站网关,完美保留了原始错误信息。
内容的提问来源于stack exchange,提问作者van
相关产品推荐
相关产品推荐

