从 Spring Integration 的 @Gateway 方法返回 ResponseEntity [英] Return ResponseEntity from Spring Integration's @Gateway method

查看:25
本文介绍了从 Spring Integration 的 @Gateway 方法返回 ResponseEntity的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有 IntegrationFlow 调用 HTTP 端点:

I have IntegrationFlow where I call HTTP endpoint:

@Bean
public IntegrationFlow getInformationFlow(RestTemplate restTemplate) {
    return IntegrationFlows.from(GET_RESPONSE_ENTITY)
            .handle(Http
                    .outboundGateway(url + "/application/{code}", restTemplate)
                    .httpMethod(GET)
                    .uriVariable("code", "payload")
                    .expectedResponseType(new ParameterizedTypeReference<ResponseEntity<Information>>() {
                    })
            ).get();
}

由于 Gateway

@MessagingGateway
public interface MyGateway {

    @Gateway(requestChannel = GET_RESPONSE_ENTITY)
    ResponseEntity<Information> getInformation(String code);

}

上面的代码抛出以下异常:

Code above throws following exception:

Caused by: org.springframework.http.converter.HttpMessageConversionException: 
Type definition error: [simple type, class org.springframework.http.ResponseEntity]; 
nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: 
Cannot construct instance of `org.springframework.http.ResponseEntity` 
(no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

Jackson 尝试反序列化为 ResponseEntity 而不是 Information

Jackson tries to deserialize into ResponseEntity instead of Information class

我的目标是先检查状态代码,然后选择检查Information 字段

My goal is to check status code first and optionally check Information fields

是否可以从@Gateway注释的方法返回ResponseEntity?

Is it possible to return ResponseEntity from method annotated by @Gateway?

推荐答案

简短回答您的问题:这取决于 MyGateway 合同实施.处理返回实际上不是网关(或任何接口 API)的责任.他们只定义合同.正确执行这样的合同已经是您的目标.

Short answer to your question: it depends on that MyGateway contract implementation. It is really not a gateway (or any interface API) responsibility to deal with returns. They define only contracts. It is already your goal to implement such a contract properly.

我的意思是,Spring 与其 EIP 组件的集成并不比常规的 Java 程序设计和架构更进一步.这个契约是一个 IntegrationFlow 作为一个实现,这只是一个特例.因此,问题不在于合同,而在于实现细节,在您的情况下是 HTTP 调用.

What I mean by this that Spring Integration with its EIP components does not go further than regular Java program design and architecture. It is just a particular case that this contract is an IntegrationFlow as an implementation. Therefore the problem is not with a contract, but rather implementation details, which is an HTTP call in your case.

所以,最好问这样的问题:

So, better to ask the question like:

如何使用 Jackson 消息转换器从 Http.outboundGateway() 返回 ResponseEntity?

How to return a ResponseEntity<Information> from the Http.outboundGateway() with a Jackson message converter?

这就是为什么我在 Gitter 上问你这个 SO 线程,以更好地了解正在发生的事情.您最初的问题具有误导性,实际上与 @MessagingGateway 无关.我什至确定这是堆栈跟踪中的一些线索,表明问题发生在 RestTemplate 调用中,而不是在 @MessagingGateway 中.

That's why I asked you on Gitter for this SO thread to better understand what is going on. Your original question is misleading and really has nothing to do with a @MessagingGateway. I'm even sure that is some clue in the stack trace that the problem happens on the RestTemplate call, not in the @MessagingGateway.

现在正在尝试帮助您解决明显的问题.

Now trying to help you to fix your explicit problem.

当存在 body 时,AbstractHttpRequestExecutingMessageHandler 不会返回 ResponseEntity:

The AbstractHttpRequestExecutingMessageHandler does not return a ResponseEntity when there is a body:

protected Object getReply(ResponseEntity<?> httpResponse) {
    HttpHeaders httpHeaders = httpResponse.getHeaders();
    Map<String, Object> headers = this.headerMapper.toHeaders(httpHeaders);
    if (this.transferCookies) {
        doConvertSetCookie(headers);
    }

    AbstractIntegrationMessageBuilder<?> replyBuilder;
    MessageBuilderFactory messageBuilderFactory = getMessageBuilderFactory();
    if (httpResponse.hasBody()) {
        Object responseBody = httpResponse.getBody();
        replyBuilder = (responseBody instanceof Message<?>)
                ? messageBuilderFactory.fromMessage((Message<?>) responseBody)
                : messageBuilderFactory.withPayload(responseBody); // NOSONAR - hasBody()
    }
    else {
        replyBuilder = messageBuilderFactory.withPayload(httpResponse);
    }
    replyBuilder.setHeader(org.springframework.integration.http.HttpHeaders.STATUS_CODE,
            httpResponse.getStatusCode());
    return replyBuilder.copyHeaders(headers);
}

仅当没有身体时.在这种情况下,这意味着没有任何内容可以映射到回复消息的 payload,因此我们使用整个 ResponseEntity.

Only if there is no body. In that case it means there is nothing to map into a payload for the reply message, therefore we use the whole ResponseEntity.

正如您在此代码段中看到的,StatusCode 被映射到 org.springframework.integration.http.HttpHeaders.STATUS_CODE 回复消息头.

As you see in this code snippet, the StatusCode is mapped to the org.springframework.integration.http.HttpHeaders.STATUS_CODE reply message header.

文档中也有一些关于此事的解释:https://docs.spring.io/spring-integration/docs/current/reference/html/http.html#using-cookies.

There is also some explanation in docs on the matter: https://docs.spring.io/spring-integration/docs/current/reference/html/http.html#using-cookies.

从这里开始,这意味着您的 expectedResponseType 只能作为 Information 类型.RestTemplate 及其 HttpMessageConverts 确实不知道如何处理要映射的 ResponseEntity 类型.

From here it means that your expectedResponseType can be only as an Information type. The RestTemplate with its HttpMessageConverts indeed doesn't know what to do with a ResponseEntity type to map.

因为如果它出现在响应中,它可能只在有效载荷中返回一个 Information,或者可能返回整个 ResponseEntity 和一个空的主体,看起来你有在返回 ResponseEntity 作为对 @MessagingGateway 调用的回复之前添加一些路由和转换逻辑.或者您可以修改该网关合同,并通过路由器或过滤器在集成流中真正实现状态代码检查 - 您的 @MessagingGateway 消费者将摆脱 HTTP 内容,例如状态代码检查和标头转换.

Since it may return just an Information in the payload if it comes in the response, or may return the whole ResponseEntity with an empty body, it looks like you have to add some routing and transformation logic before returning a ResponseEntity<Information> as a reply to your @MessagingGateway call. Or you can revise that gateway contract and really implement a status code check in the integration flow via router or filter - and your @MessagingGateway consumer would be free from the HTTP stuff like status code checking and headers conversion.

尽管在 AbstractHttpRequestExecutingMessageHandler 上有一些选项总是返回整个 ResponseEntity 作为有效负载可能没有什么坏处.随时提出 GH 问题,我们会考虑尽快实施!

Although it might not hurt to have some option on the AbstractHttpRequestExecutingMessageHandler to always return the whole ResponseEntity as a payload. Feel free to raise a GH issue a we will consider to implement it sooner than later!

这篇关于从 Spring Integration 的 @Gateway 方法返回 ResponseEntity的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆