当前位置: 首页 > 知识库问答 >
问题:

在Spring WebFlux中进行异步SOAP调用

公羊喜
2023-03-14

我有一个使用WebFlux和REST API的反应性Spring应用程序。每当用户调用我的API,我都需要调用一个公开WSDL的SOAP服务,执行一些操作并返回结果。

如何将对SOAP服务的调用与反应性WebFlux框架结合起来?

在我看来,我可以用两种不同的方式来做:

  1. 使用WebFlux的WebClient构造并发送SOAP消息。
  2. 在Mono/flux中使用WebServiceGatewaySupport包装同步调用。
public class MySoapClient extends WebServiceGatewaySupport {

    public QueryResponse execute() {
        Query query = new ObjectFactory().createQuery();
        // Further create and set the domain object here from the wsdl2java generated classes       
        return (QueryResponse) getWebServiceTemplate().marshalSendAndReceive(query);
    }
}

有人能分享从WebFlux控制器到进行SOAP调用并异步返回的完整示例吗?我觉得我错过了一些重要的东西。

共有1个答案

西门凯康
2023-03-14

我有同样的目标,但没有WSDL文件。作为输入,我有endpoint和XSD文件,它定义了我应该发送的请求方案。这是我的一段代码。

首先,让我们定义我们的SOPA WebClient bean(以避免每次需要调用时都创建它)

@Bean(name = "soapWebClient")
public WebClient soapWebClient(WebClient.Builder webClientBuilder) {
        String endpoint = environment.getRequiredProperty(ENDPOINT);
        log.info("Initializing SOAP Web Client ({}) bean...", endpoint);

        return webClientBuilder.baseUrl(endpoint)
                               .defaultHeader(CONTENT_TYPE, "application/soap+xml")
                               //if you have any time limitation put them here
                               .clientConnector(getWebClientConnector(SOAP_WEBCLIENT_CONNECT_TIMEOUT_SECONDS, SOAP_WEBCLIENT_IO_TIMEOUT_SECONDS))
                               //if you have any request/response size limitation put them here as well
                               .exchangeStrategies(ExchangeStrategies.builder()
                                                                     .codecs(configurer -> configurer.defaultCodecs()
                                                                                                     .maxInMemorySize(MAX_DATA_BUFFER_SIZE))
                                                                     .build())
                               .build();
}

public static ReactorClientHttpConnector getWebClientConnector(int connectTimeoutSeconds, int ioTimeoutSeconds) {
        TcpClient tcpClient = TcpClient.create()
                                       .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeoutSeconds * 1000)
                                       .doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(ioTimeoutSeconds))
                                                                  .addHandlerLast(new WriteTimeoutHandler(ioTimeoutSeconds)));
        return new ReactorClientHttpConnector(HttpClient.from(tcpClient));
}

现在您可以使用客户机进行SOAP调用,如下所示:

@Slf4j
@Component
public class SOAPClient {

    private final WebClient soapWebClient;

    public SOAPClient(@Qualifier("soapWebClient") WebClient soapWebClient) {
        this.soapWebClient = soapWebClient;
    }

    public Mono<Tuple2<HttpStatus, String>> send(String soapXML) {
        return Mono.just("Request:\n" + soapXML)
                   .doOnNext(log::info)
                   .flatMap(xml -> soapWebClient.post()
                                                .bodyValue(soapXML)
                                                .exchange()
                                                .doOnNext(res -> log.info("response status code: [{}]", res.statusCode()))
                                                .flatMap(res -> res.bodyToMono(String.class)
                                                                   .doOnNext(body -> log.info("Response body:\n{}", body))
                                                                   .map(b -> Tuples.of(res.statusCode(), b))
                                                                   .defaultIfEmpty(Tuples.of(res.statusCode(), "There is no data in the response"))))
                   .onErrorResume(ConnectException.class, e -> Mono.just(Tuples.of(SERVICE_UNAVAILABLE, "Failed to connect to server"))
                                                                   .doOnEach(logNext(t2 -> log.warn(t2.toString()))))
                   .onErrorResume(TimeoutException.class, e -> Mono.just(Tuples.of(GATEWAY_TIMEOUT, "There is no response from the server"))
                                                                   .doOnEach(logNext(t2 -> log.warn(t2.toString()))));
    }

}

这里要提到的一件重要事情是,soapxml显然应该是SOAP协议定义的格式。更具体地说,消息至少应该以soap:envelope标记开始和结束,并包含所有其他数据。另外,请注意您将要使用的SOAP协议版本,因为它定义了允许在信封内使用哪些标记,哪些不允许使用。我的代码是1.1,下面是它的规范https://www.w3.org/tr/2000/note-soap-20000508/#_toc478383494

干杯

 类似资料:
  • 我需要进行异步调用,并使用其中存在的一些值对同一服务进行多次调用。将这些调用的响应与第一个调用结合起来,然后返回。 例如,当我第一次调用时,我会在JSON下面看到一个ID列表。现在,我必须使用这些ID对一个服务进行多次调用,并列出它们的响应列表,然后通过在同一个JSON中添加它们将其发送到下游。 我试过使用zipWhen和 但是结果列表总是以空或空的形式出现。我们如何才能做到这一点?我是不是漏了什

  • 问题内容: 按照目前的情况,这个问题不适合我们的问答形式。我们希望答案会得到事实,参考或专业知识的支持,但是这个问题可能会引起辩论,争论,民意调查或扩展讨论。如果您认为此问题可以解决并且可以重新提出,请访问帮助中心以获取指导。 7年前关闭。 假设Adwords是Google的事物,而Go是Google的事物,那么用Go编写的Adwords API版本需要多长时间? 与此问题相关的另一个问题是:是否

  • 问题内容: 我正在Flask中编写一个应用程序,除了同步和阻塞之外,它的运行情况非常好。我特别有一项任务,该任务调出第三方API,该任务可能需要几分钟才能完成。我想拨打该电话(实际上是一系列电话)并使其运行。同时控制权返回给Flask。 我的看法如下: 现在,我要做的就是 运行并提供在方法返回时要执行的回调,而Flask可以继续处理请求。这是我需要Flask异步运行的唯一任务,并且我想就如何最好地

  • 如何发送头? 如何解决证书问题?

  • 问题内容: 我想在每次执行Flask路由时执行一个异步函数。为什么函数从不执行? 我还尝试将阻塞调用放在单独的线程中。但是它仍然没有调用该函数。 问题答案: 你可以将一些异步功能整合到Flask应用中,而不必完全将其转换为异步。 这将阻止Flask响应,直到异步函数返回为止,但是它仍然允许你做一些聪明的事情。我已经使用此模式使用aiohttp并行执行许多外部请求,然后在完成它们之后,我回到传统的f

  • 我开始学钩子了。但是我不明白异步调用是如何工作的。早些时候我被使用 然后调用我的,但是我应该用useDispat()做什么?如果我只是调用 然后我的< code > foo() don t < code > console . log(2) 我正在使用thunk