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

javax.net.ssl。SSLException:SSLEngine已关闭SSLEngie已在webclient(Springboot)中关闭

邵正雅
2023-03-14

我在springboot应用程序中使用webclient来调用外部restful web服务。间歇性地获取此异常。

javax.net.ssl.SSLException: SSLEngine closed already SSLEngine closed already

在收到此异常之前,我在日志中看到以下警告。

javax.net.ssl.SSLException:
   at io.netty.handler.ssl.SslHandler.wrap (SslHandler.java854)
   at io.netty.handler.ssl.SslHandler.wrapAndFlush (SslHandler.java811)
   at io.netty.handler.ssl.SslHandler.flush (SslHandler.java792)
   at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0 (AbstractChannelHandlerContext.java750)
   at io.netty.channel.AbstractChannelHandlerContext.invokeFlush (AbstractChannelHandlerContext.java742)
   at io.netty.channel.AbstractChannelHandlerContext.flush (AbstractChannelHandlerContext.java728)
   at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.flush (CombinedChannelDuplexHandler.java531)
   at io.netty.channel.ChannelOutboundHandlerAdapter.flush (ChannelOutboundHandlerAdapter.java125)
   at io.netty.channel.CombinedChannelDuplexHandler.flush (CombinedChannelDuplexHandler.java356)
   at io.netty.channel.AbstractChannelHandlerContext.invokeFlush0 (AbstractChannelHandlerContext.java750)
   at io.netty.channel.AbstractChannelHandlerContext.invokeWriteAndFlush (AbstractChannelHandlerContext.java765)
   at io.netty.channel.AbstractChannelHandlerContext.write (AbstractChannelHandlerContext.java790)
   at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush (AbstractChannelHandlerContext.java758)
   at io.netty.channel.AbstractChannelHandlerContext.writeAndFlush (AbstractChannelHandlerContext.java808)
   at io.netty.channel.DefaultChannelPipeline.writeAndFlush (DefaultChannelPipeline.java1025)
   at io.netty.channel.AbstractChannel.writeAndFlush (AbstractChannel.java294)
   at reactor.netty.http.HttpOperations.lambda$send$0 (HttpOperations.java123)
   at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext (MonoFlatMap.java118)
   at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext (FluxMapFuseable.java121)
   at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.onNext (FluxContextStart.java96)
   at reactor.core.publisher.Operators$ScalarSubscription.request (Operators.java2344)
   at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.request (FluxContextStart.java125)
   at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request (FluxMapFuseable.java162)
   at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe (MonoFlatMap.java103)
   at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe (FluxMapFuseable.java90)
   at reactor.core.publisher.FluxContextStart$ContextStartSubscriber.onSubscribe (FluxContextStart.java90)
   at reactor.core.publisher.MonoJust.subscribe (MonoJust.java54)
   at reactor.core.publisher.Mono.subscribe (Mono.java4213)
   at reactor.core.publisher.FluxConcatIterable$ConcatIterableSubscriber.onComplete (FluxConcatIterable.java146)
   at reactor.core.publisher.FluxConcatIterable.subscribe (FluxConcatIterable.java60)
   at reactor.core.publisher.MonoFromFluxOperator.subscribe (MonoFromFluxOperator.java81)
   at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext (MonoFlatMap.java150)
   at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext (FluxSwitchIfEmpty.java67)
   at reactor.core.publisher.Operators$MonoSubscriber.complete (Operators.java1782)
   at reactor.core.publisher.MonoSingle$SingleSubscriber.onComplete (MonoSingle.java171)
   at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete (FluxMapFuseable.java144)
   at reactor.core.publisher.FluxJust$WeakScalarSubscription.request (FluxJust.java101)
   at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request (FluxMapFuseable.java162)
   at reactor.core.publisher.MonoSingle$SingleSubscriber.request (MonoSingle.java94)
   at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set (Operators.java2152)
   at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe (Operators.java2026)
   at reactor.core.publisher.MonoSingle$SingleSubscriber.onSubscribe (MonoSingle.java114)
   at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe (FluxMapFuseable.java90)
   at reactor.core.publisher.FluxJust.subscribe (FluxJust.java70)
   at reactor.core.publisher.InternalMonoOperator.subscribe (InternalMonoOperator.java64)
   at reactor.core.publisher.MonoDefer.subscribe (MonoDefer.java52)
   at reactor.netty.http.client.HttpClientConnect$HttpIOHandlerObserver.onStateChange (HttpClientConnect.java442)
   at reactor.netty.ReactorNetty$CompositeConnectionObserver.onStateChange (ReactorNetty.java518)
   at reactor.netty.resources.PooledConnectionProvider$DisposableAcquire.run (PooledConnectionProvider.java633)
   at io.netty.util.concurrent.AbstractEventExecutor.safeExecute (AbstractEventExecutor.java164)
   at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks (SingleThreadEventExecutor.java472)
   at io.netty.channel.nio.NioEventLoop.run (NioEventLoop.java500)
   at io.netty.util.concurrent.SingleThreadEventExecutor$4.run (SingleThreadEventExecutor.java989)
   at io.netty.util.internal.ThreadExecutorMap$2.run (ThreadExecutorMap.java74)
   at io.netty.util.concurrent.FastThreadLocalRunnable.run (FastThreadLocalRunnable.java30)
   at java.lang.Thread.run (Thread.java748)

这是完整的堆栈跟踪:

reactor.core.Exceptions$ReactiveException:
       at reactor.core.Exceptions.propagate (Exceptions.java393)
       at reactor.core.publisher.BlockingSingleSubscriber.blockingGet (BlockingSingleSubscriber.java97)
       at reactor.core.publisher.Mono.block (Mono.java1680)
       at .service.CustomWebClient.callTarget (CustomWebClient.java48)
       at .service.MessageServiceImpl.sendMessageToTargetGetAcknowledgement (MessageServiceImpl.java101)
       at .service.MessageServiceImpl.transferMessagesFromSourceToTarget (MessageServiceImpl.java53)
       at .controller.MessageController.processMessageFromSourceThread3 (MessageController.java71)
       at .controller.MessageController$$FastClassBySpringCGLIB$$c25da1d1.invoke (<generated>)
       at org.springframework.cglib.proxy.MethodProxy.invoke (MethodProxy.java218)
       at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint (CglibAopProxy.java771)
       at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (ReflectiveMethodInvocation.java163)
       at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed (CglibAopProxy.java749)
       at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction (TransactionAspectSupport.java367)
       at org.springframework.transaction.interceptor.TransactionInterceptor.invoke (TransactionInterceptor.java118)
       at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed (ReflectiveMethodInvocation.java186)
       at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed (CglibAopProxy.java749)
       at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept (CglibAopProxy.java691)
       at .controller.MessageController$$EnhancerBySpringCGLIB$$7a54eddc.processMessageFromSourceThread3 (<generated>)
       at sun.reflect.GeneratedMethodAccessor63.invoke
       at sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java43)
       at java.lang.reflect.Method.invoke (Method.java498)
       at org.springframework.scheduling.support.ScheduledMethodRunnable.run (ScheduledMethodRunnable.java84)
       at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run (DelegatingErrorHandlingRunnable.java54)
       at java.util.concurrent.Executors$RunnableAdapter.call (Executors.java511)
       at java.util.concurrent.FutureTask.runAndReset (FutureTask.java308)
       at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301 (ScheduledThreadPoolExecutor.java180)
       at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run (ScheduledThreadPoolExecutor.java294)
       at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java1149)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java624)
       at java.lang.Thread.run (Thread.java748)
    Inner exception javax.net.ssl.SSLException handled at reactor.core.Exceptions.propagate:
       at io.netty.handler.ssl.SslHandler.wrap (SslHandler.java854)

这是MessageServiceImpl.java

package service;
import org.hibernate.exception.SQLGrammarException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.InvalidDataAccessResourceUsageException;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;


@Service
public class MessageServiceImpl implements MessageService {

  private static final Logger LOGGER = LoggerFactory.getLogger(MessageServiceImpl.class);

  @Autowired
  private MessageRepository repository;

  @Value("${TARGET_ENDPOINT}")
  private String baseEndPoint;

  @Autowired
  private CustomWebClient webClient;

  
  public Message transferMessagesFromSourceToTarget()
       {

    Message message = new Message();
    try {

      message = getMessageFromSource();
      //some code....   
      
      sendAcknowledgementToSource(message);
      //some code....
     

    } catch (HttpServerErrorException | HttpClientErrorException e) {
      //somecode

    } catch (InvalidDataAccessResourceUsageException | SQLGrammarException  e) {
      //somecode
    }

    return message;

  }

 
  private Message getMessageFromSource() {
    return repository.getSourceMessageFromStroredProcedureCall();
  }

  
  private Message sendMessageToTargetGetAcknowledgement(Message message) {
    
    ResponseEntity<String> response = null;
    
    response = webClient.callTarget(baseEndPoint+ message.getHostURL(),message);
   
    message.setHttpStatus(response.getStatusCodeValue());
    
    return message;
  }

}

这里是客户端组件类

package service;

import XYZ.model.Message;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

/
@Component
public class CustomWebClient {

  private final WebClient webClient;

  /**
   * Constructor to autowire WebClient instance
   * @param webClient webclient instance
   */
  @Autowired
  public CustomWebClient(WebClient webClient){
    this.webClient = webClient;
  }

  
  public ResponseEntity<String> callTarget(String baseEndPoint, Message message) {
    String response = webClient.post().uri(baseEndPoint)
        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE)
        .body(BodyInserters.fromValue(message.getMessage()))
        .retrieve()
        .onStatus(HttpStatus::is5xxServerError, serverError ->
            Mono.error(new HttpServerErrorException(serverError.statusCode())))
        .onStatus(HttpStatus::is4xxClientError, clientError ->
            Mono.error(new HttpClientErrorException(clientError.statusCode())))
        .bodyToMono(String.class).block();
    return new ResponseEntity<>(response, HttpStatus.OK);
  }
}

在下面的配置中,我在SSLContext中添加了信任存储。

package xyz.conf;

import static java.nio.charset.StandardCharsets.US_ASCII;

import xyz.constants.Constants;
import xyz.service.ResourceReader;
import io.netty.channel.ChannelOption;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.timeout.ReadTimeoutHandler;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.security.auth.x500.X500Principal;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.netty.http.client.HttpClient;

/**
 * Webclient configuration
 */
@Configuration
public class WebClientConfig {

  private String user;

  private String pass;

  private ResourceReader resourceReader;

  /**
   * Constructor to autowire ResourceReader
   * @param resourceReader ResourceReader object
   */
  @Autowired
  public WebClientConfig(ResourceReader resourceReader) {
    this.resourceReader = resourceReader;
  }

  @Value("${USER}")
  public void setuser(String user) {
    this.user = user;
  }

  @Value("${PASSWD}")
  public void setpass(String pass) {
    this.pass = pass;
  }

  private static final Logger LOGGER = LoggerFactory.getLogger(WebClientConfig.class);

  @Bean
  WebClient getWebClient () throws IOException, KeyManagementException, NoSuchAlgorithmException, KeyStoreException, CertificateException {
    LOGGER.info("WebClient configuration started.");
    TrustManagerFactory trustManagerFactory =
        TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    KeyStore trustStore = getTrustStore(resourceReader.readTrustStoreConfig());

    trustManagerFactory.init(trustStore);
    SSLContext context = SSLContext.getInstance("TLSv1.2");
    context.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());

    SslContext sslContext = SslContextBuilder
        .forClient()
        .trustManager(trustManagerFactory)
        .build();

    HttpClient httpClient = HttpClient.create().secure( t -> t.sslContext(sslContext) );
    httpClient = httpClient.tcpConfiguration(tcpClient -> tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000));
    httpClient = httpClient.responseTimeout(Duration.ofMillis(30000));

    LOGGER.info("WebClient configured successfully..");
    ReactorClientHttpConnector reactorClientHttpConnector = new ReactorClientHttpConnector(httpClient);
    return WebClient.builder().clientConnector(reactorClientHttpConnector)
        .defaultHeaders(header -> header.setBasicAuth(user, pass))
        .build();

  }

  private KeyStore getTrustStore(String certificateChainPem)
      throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {

    KeyStore keyStore = null;
    keyStore = KeyStore.getInstance("JKS");
    keyStore.load(null, null);

    List<X509Certificate> certificates = readCertificateChain(certificateChainPem);
    for (X509Certificate certificate : certificates) {
      X500Principal principal = certificate.getSubjectX500Principal();
      keyStore.setCertificateEntry(principal.getName("RFC2253"), certificate);
    }

    return keyStore;
  }

  private List<X509Certificate> readCertificateChain(String certificateChainPem)
      throws CertificateException {
    List<X509Certificate> certificates = new ArrayList<>();

    Matcher matcher = Constants.CERT_PATTERN.matcher(certificateChainPem);
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");

    int start = 0;
    while (matcher.find(start)) {
      byte[] buffer = base64Decode(matcher.group(1));
      certificates.add((X509Certificate) certificateFactory
          .generateCertificate(new ByteArrayInputStream(buffer)));
      start = matcher.end();
    }

    return certificates;
  }

  private byte[] base64Decode(String base64) {
    return java.util.Base64.getMimeDecoder().decode(base64.getBytes(US_ASCII));
  }    

}

下面是应用程序属性文件

logging.level.org.springframework=INFO

TARGET_ENDPOINT=XYZ
USER=XYZ
PASSWD=XYZ

#maxidle timeout for netty pool
reactor.netty.pool.maxIdleTime=3000

我已经尝试通过下面链接中给出的解决方案来解决这个问题,但是没有成功。https://github.com/reactor/reactor-netty/issues/782

以下是版本详细信息:-

启动版本:2.3.3.RELEASE

共有1个答案

邹俊友
2023-03-14

我在 Spring boot 2.4.12 和 reactor-netty-http-1.0.12 上看到了同样的问题。重新启动服务器解决了问题。

我认为< code > SSLEngine closed has 可能不是由于一个特定的问题,而是基于每个使用案例。最简单的

 类似资料:
  • 问题内容: 我正在尝试使用Hibernate 5创建或更新用户,并且抛出以下异常:org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl@779de014已关闭 我正在使用以下技术: Spring 4 *Dormancy 5 *Marvin *Erosion 这是我的: 这是我的: 错误信息: Hibernate xml文

  • 我想使用stream getfirst方法两次,但是出现了一个错误,即(java.lang.IllegalStateException:stream已经被操作或关闭),并且这个流代码以此处命名的注释开始。

  • 我读了一个关于docker的很好的问题--答案概述了docker的实现细节。我想知道在Windows平台上是否可以做类似的事情。 Docker的Windows替代方案是否存在? 理论上是否可以使用其他(基于Windows的)组件来构建它? 更新1: 稍微相关的问题(沙箱):Windows平台是否有轻量级、可编程的沙箱API? 更新2:: 有关如何在windows上安装docker的信息(无关)-官

  • 所以我的问题是:我通常把我的笔记本电脑连接到外部屏幕上,一切正常,直到我需要把我的笔记本电脑带到大学去做进度报告。当我的笔记本电脑没有连接到外部屏幕时,imshow显示的窗口在底部被切断,如图所示。 以前有人遇到过这个问题吗?如果有,你能分享如何解决这个问题吗?我的笔记本电脑使用windows 10,python 3.6.4和opencv 3.3.0。 我当前的代码有点长,所以我将在这里给出流程:

  • 想改进这个问题吗 通过编辑此帖子,更新问题,使其只关注一个问题。 ** ** 之间的所有文本都已弃用。我不知道应该用什么来替换它。你能帮我一些忙吗?我是初学者,只是制作一个应用程序来与我的树莓派交流。 公共类JSONParser {

  • 我正在搜索一个程序,可以接收和发射caracters与rs232连接。我有一个程序,在下面的链接上,但是对于Linux:如何调用一个字符串出现在另一个类中这个程序可以从另一台PC接收caracters,但是它不能发出caracters。我试着把,在公共静态虚空主,发送caracters的功能,但它不工作。你有解决办法吗?谢谢