Spring integration: preserve http error code and b

2019-09-15 10:59发布

问题:

I have an inbound http gateway whose incoming message is passed to an outbound http gateway (using integration java dsl).

When the outbound gateway response has http status 200, the outbound response goes back to the caller of the inbound gateway as expected.

But when the outbound gateway responds with specific client errors like 423 locked or 403 forbidden, the caller of the inbound gateway receives 500 and a body message that contains an exception as String.

I understand that this is because SI handles outbound http errors as exceptions. But in my case I need to pass through the error status and the response body that comes with the outbound response back to the caller of the inbound gateway, for the specific error codes. How do I do that?

回答1:

We call this scenario as HTTP Proxy and have some test-case on the matter: https://github.com/spring-projects/spring-integration/blob/master/spring-integration-http/src/test/java/org/springframework/integration/http/dsl/HttpDslTests.java

I've just done some investigation and here is what you need:

IntegrationFlows
    .from(Http.inboundGateway("/service")
            .requestMapping(r -> r.params("name"))
            .errorChannel("httpProxyErrorFlow.input"))
...

@Bean
public IntegrationFlow httpProxyErrorFlow() {
    return f -> f
            .transform(Throwable::getCause)
            .<HttpClientErrorException>handle((p, h) ->
                    MessageBuilder.withPayload(p.getResponseBodyAsString())
                            .setHeader(HttpHeaders.STATUS_CODE, p.getStatusCode())
                            .build());
}

We have to handle downstream errors on the Inbound Gateway level. For this purpose Spring Integration suggest the errorChannel functionality.

That httpProxyErrorFlow provides some logic on the matter. First of all we know that the message for the errorChannel is ErrorMessage and its payload is MessagingException - as a result of wrapping HttpClientErrorException in the HttpRequestExecutingMessageHandler. So, with the .transform() we drill down to the desired exception and in the .handle() we build a new message based on the HttpClientErrorException content.

The HttpRequestHandlingMessagingGateway is able to process such a message properly and set a desired status code to the response:

protected final Object setupResponseAndConvertReply(ServletServerHttpResponse response, Message<?> replyMessage) {
    getHeaderMapper().fromHeaders(replyMessage.getHeaders(), response.getHeaders());
    HttpStatus httpStatus = this.resolveHttpStatusFromHeaders(replyMessage.getHeaders());
    if (httpStatus != null) {
        response.setStatusCode(httpStatus);
    }

http://docs.spring.io/spring-integration/docs/4.3.11.RELEASE/reference/html/http.html#http-response-statuscode