Как решить проблему НЕТ ВЫВОДА или ЗАГОЛОВКА ОТВЕТА КАНАЛА

Для трехсторонней связи между двумя внешними приложениями, созданными с использованием чего-то другого, и моим приложением Springboot.

  • Внешний клиент 1 всегда инициирует связь через сокет TCP.
  • Приложение Springboot использует TCPInboundGateway для получения информации.
  • Приложение Springboot использует TCPOutboundGateway для отправки данных внешнему клиенту 2.
  • Ответ получен от внешнего клиента 2
  • Я хочу отправить этот ответ внешнему клиенту1.
  • Я получаю заголовок «Нет вывода» или «Ответ канала».

Я предполагаю, что TcpInboundGateway, созданный в первом экземпляре, представляет собой запрос-ответ, поэтому он должен ждать ответа, который внешний клиент 2 отправит ему через мое приложение.

В службе, которая получает ответ от TcpOutboundGateway, я Предполагается, что просто установив выходной канал в этой службе с тем же именем, что и ответный канал в tcpInboundGateway, соединение будет установлено. Но это не работает. Так почему же нет заголовка вывода или ответа?

 //The inbound gateway
  @Bean
     public TcpInboundGateway 
     tcpInboundGateway(AbstractServerConnectionFactory 
     serverConnectionFactory) {
    TcpInboundGateway gateway = new TcpInboundGateway();
    gateway.setConnectionFactory(serverConnectionFactory);
    gateway.setRequestChannel(requestChannel());
    gateway.setLoggingEnabled(true);
    gateway.setReplyChannel(backToPos());
    gateway.setReplyTimeout(60000);
    return gateway;
}

// The outbound gateway
@Bean
@ServiceActivator(inputChannel = "tcpUpslOutgateChannel")
public MessageHandler tcpOutboundGateway() {
    TcpOutboundGateway gateway = new TcpOutboundGateway();
    gateway.setConnectionFactory(upslClientConnectionFactory());
    gateway.setUnsolicitedMessageChannel(unsolicitedChannel());
    gateway.setOutputChannelName("forUpslReplyChannel");
    return gateway;
}

//Service that handles the response
  @ServiceActivator(inputChannel = "forUpslReplyChannel", 
 outputChannel = "backToPos")
public String 
 processResponseMessageFromUpslForPurchase(Message<String> 
 messageFull) {
   return processResponseMessageForPurchase(messageFull);
}

Другая конфигурация включает каналы и обработчики сервисов... Ниже приведены логи

024-07-12T08:47:07.307+01:00  INFO 23544 --- [terminal-management] [pool-2-thread-2] c.r.t.s.t.ResponseService                : still in the response service
2024-07-12T08:47:07.311+01:00 DEBUG 23544 --- [terminal-management] [pool-2-thread-2] o.s.i.ip.tcp.TcpInboundGateway           : failure occurred in gateway sendAndReceive: error occurred in message handler [org.springframework.integration.handler.BridgeHandler@25207619]
2024-07-12T08:47:07.311+01:00 ERROR 23544 --- [terminal-management] [pool-2-thread-2] o.s.i.i.tcp.connection.TcpNetConnection  : Exception sending message: GenericMessage [payload=byte[809], headers = {ip_tcp_remotePort=55560, ip_connectionId=127.0.0.1:55560:30002:6a5442c5-0c0d-4217-aab2-fe49776b6d6c, ip_localInetAddress=/127.0.0.1, ip_address=127.0.0.1, id=c841c491-79dc-5e17-4e95-6f7ac6052b79, ip_hostname=127.0.0.1, timestamp=1720770425566}]

org.springframework.messaging.MessageHandlingException: error occurred in message handler [org.springframework.integration.handler.BridgeHandler@25207619]
    at org.springframework.integration.support.utils.IntegrationUtils.wrapInHandlingExceptionIfNecessary(IntegrationUtils.java:191) ~[spring-integration-core-6.3.0.jar:6.3.0]
    at org.springframework.integration.handler.AbstractMessageHandler.doHandleMessage(AbstractMessageHandler.java:108) 
        at org.springframework.integration.ip.tcp.connection.TcpNetConnection.run(TcpNetConnection.java:206) ~[spring-integration-ip-6.3.0.jar:6.3.0]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) ~[na:na]
    at java.base/java.lang.Thread.run(Thread.java:840) ~[na:na]
Caused by: org.springframework.messaging.core.DestinationResolutionException: no output-channel or replyChannel header available
    at org.springframework.integration.handler.AbstractMessageProducingHandler.sendOutput(AbstractMessageProducingHandler.java:504) ~[spring-integration-core-6.3.0.jar:6.3.0]
    at org.springframework.integration.handler.AbstractMessageProducingHandler.doProduceOutput(AbstractMessageProducingHandler.java:357) ~[spring-integration-core-6.3.0.jar:6.3.0]
    at org.springframework.integration.handler.AbstractMessageProducingHandler.produceOutput(AbstractMessageProducingHandler.java:286) ~[spring-integration-core-6.3.0.jar:6.3.0]

Пожалуйста, добавляйте код, а не изображения кода (или журналы): см. Почему бы не загружать изображения ошибок кода, когда задаете вопрос. Отредактируйте вопрос и включите фрагменты кода.

J Asgarov 10.07.2024 09:46

В вашем клиентском приложении происходит что-то еще. Судя по вашему скриншоту, эта ошибка появилась через 2 секунды. Итак, похоже, что по какой-то причине удалено, например. исключение при отправке. Вы можете включить уровень ведения журнала trace для категории org.springframework.integration.ip.tcp, чтобы наблюдать за активностью клиента в этой категории TcpOutboundGateway.

Artem Bilan 10.07.2024 18:30

Итак, я нашел кое-что связанное с переполнением стека. Я решил использовать сотрудничающие адаптеры для получения и ответа на клиент (serviceA) и исходящий шлюз для отправки и получения ответа от сервера (serviceB). Я получаю сообщение об ошибке с исходящим сокетом и соответствующим ответом. Кажется, я не могу реализовать исправление, рекомендованное в этом посте ниже. На самом деле, я еще раз отредактирую вопрос stackoverflow.com/questions/41568806/…

serethewind 11.07.2024 10:32

Это слишком много пользовательского кода, который трудно переварить. Почему вы не можете просто использовать TcpInboundGateway и TcpOutboundGateway в Службе B для вызова Службы C? Служба А также может просто использовать TcpOutboundGateway. Таким образом, ответ от Службы C будет таким же TcpInboundGateway. Этот будет ретранслировать ответ обратно на свое соединение до Службы A. Не уверен, зачем вам нужны адаптеры взаимодействующих каналов, поскольку похоже, что это вам не подходит.

Artem Bilan 11.07.2024 20:54

@ArtemBilan, надеюсь, у тебя был отличный день. Я воспользовался вашим советом использовать исходящий шлюз и входящий шлюз, но теперь возникла ошибка: нет заголовка вывода или ответа канала. Я чувствую, что я ближе. Я отредактировал вопрос. Пожалуйста, просмотрите его. Ваше здоровье

serethewind 12.07.2024 10:16
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Версия Java на основе версии загрузки
Версия Java на основе версии загрузки
Если вы зайдете на официальный сайт Spring Boot , там представлен start.spring.io , который упрощает создание проектов Spring Boot, как показано ниже.
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
1
5
77
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Шаблон запрос-ответ в Spring Integration реализован через EIP обратного адреса: https://www.enterpriseintegrationpatterns.com/patterns/messaging/ReturnAddress.html.

Итак, когда мы создаем сообщение в нисходящем направлении от входного шлюза, заголовок replyChannel заполняется.

Этот AbstractMessageProducingHandler в вашей трассировке стека может извлечь этот заголовок из сообщения запроса, чтобы правильно доставить ответ на ожидающий сеанс шлюза.

Итак, по сути, нам вообще не нужен gateway.setReplyChannel(backToPos()); на входном шлюзе. У меня даже есть открытая проблема с полным прекращением его поддержки: https://github.com/spring-projects/spring-integration/issues/3985.

Итак, ваш активатор услуги мог бы быть проще:

@ServiceActivator(inputChannel = "forUpslReplyChannel")

Никаких outputChannel вообще. Это оптимизирует не только ваш код, но и поведение во время выполнения, поскольку не будет необходимости в дополнительном мосте между реальным каналом ответа и соответствующим значением заголовка.

Однако оказывается, что сообщение запроса для этого forUpslReplyChannel больше не имеет replyChannel заголовка. Судя по всему, между tcpOutboundGateway и processResponseMessageFromUpslForPurchase у вас есть еще какие-то шаги. Итак, вы создаете новый Message, но теряете заголовки сообщения запроса.

TcpOutboundGateway не делает этого сам по себе, потому что его логика такая:

/**
 * Subclasses may override this. True by default.
 * @return true if the request headers should be copied.
 */
protected boolean shouldCopyRequestHeaders() {
    return true;
}

Я считаю, что уровень ведения журнала отладки для категории org.springframework.integration (или WireTap с подписчиком LoggingHandler) — это хороший способ отслеживать, что происходит с вашим сообщением, когда оно проходит через поток: https://docs.spring.io/spring -integration/reference/channel/configuration.html#channel-wiretap

Спасибо @Артем. Теперь это работает. Пожалуйста, я пытаюсь подключиться к внешнему серверу с помощью SSL. Я думаю, что все сделал правильно, но получаю сообщение «Альтернативное имя ошибки отсутствует». Это ссылка на него, я тоже поделился журналами ошибок stackoverflow.com/questions/78744719/…

serethewind 13.07.2024 20:58

Другие вопросы по теме