稳健的一休哥 2022-09-26 14:39
浏览 31
已结题

okhttp请求报连接重置问题

背景&环境

与第三方方使用https接口传递部分订单数据, 我方为客户端, 对方提供数据接收服务
接口调用时偶尔会出现 Connection reset & Connection reset by peer: socket write error 错误, 也有数据下发成功的时候
环境: okhttp3 4.8.1

相关代码:
// 信任任意的https证书
private OkHttpClient strongOkHttpClient() throws IOException {
  try {
    final TrustManager[] trustAllCerts = new TrustManager[]{
      new X509TrustManager() {
        @Override
        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {}

        @Override
        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {}

        @Override
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
          return new java.security.cert.X509Certificate[]{};
        }
      }
    };

    final SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
    final javax.net.ssl.SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
    OkHttpClient.Builder builder = new OkHttpClient.Builder();
    builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);

    builder.hostnameVerifier(new HostnameVerifier() {
      @Override
      public boolean verify(String hostname, SSLSession session) {
        return true;
      }
    });

    return builder
      .connectTimeout(180, TimeUnit.SECONDS)
      .readTimeout(180, TimeUnit.SECONDS)
      .writeTimeout(180, TimeUnit.SECONDS)
      .build();
  } catch (Exception e) {
    throw new IOException(e);
  }
}

// http请求下发逻辑
public void send(String accNo, String vouchId) {
  // 获取请求参数数据
  String dbName = ufCoProperties.getAccountMap().get(accNo);
  List<POInfo> poInfoList = poDao.listPO(accNo, dbName, vouchId);
  poInfoList.forEach(item -> {
    item.setSignature(tbOrderProperties.getAppKey());
  });

  log.info("采购订单接口下发数据: {}", JSON.toJSONString(poInfoList));

  // 构建请求体
  RequestBody requestBody = new RequestBody() {
    @Override
    public MediaType contentType() {
      return MediaType.parse("application/json");
    }

    @Override
    public void writeTo(BufferedSink sink) throws IOException {
      sink.writeUtf8(JSON.toJSONString(poInfoList));
    }
  };

  log.info("请求URL: {}", tbOrderProperties.getUrl());
  // 构建Http请求
  Request request = new Request.Builder()
          .url(tbOrderProperties.getUrl())
          .header("Authorization", tbOrderProperties.getToken())
          .post(requestBody)
          .build();

  String sendMessage;

  // 发送Http请求
  try {
    OkHttpClient client = strongOkHttpClient();

    // 在此处发起http请求时报错
    Response response = client.newCall(request).execute();

    String responseBody = response.body().string();
    log.info("HTTP请求处理完成 - 响应数据: {}", responseBody);

    Map<String,Object> result = JSON.parseObject(responseBody, Map.class);
    boolean success = (boolean) result.get("success");
    Object data = result.get("data");
    if(success) {
      sendMessage = "下发成功";
    } else {
      sendMessage = String.format("下发失败: %s", data);
    }
  } catch (IOException e) {
    log.error("HTTP请求处理失败 - IO异常: {}", e.getMessage(), e);
    sendMessage = "HTTP请求处理失败 - IO异常: " + e.getMessage();
  }

  // 回写单据处理结果
  poDao.updatePOByCode(dbName, vouchId, sendMessage);
}
个人思考

参考网上部分关于Connection reset的相关回答,均表示是由服务器端关闭连接后,我方客户端服务仍通过接口读写数据导致的,那么按道理来说,服务器端应该是已经接收到请求了,然后在接收到请求之后因为种种原因关闭了连接导致客户端报错。
实际情况: 对接方告知我方并未收到接口请求

错误日志:
javax.net.ssl.SSLException: java.net.SocketException: Connection reset
    at sun.security.ssl.Alert.createSSLException(Alert.java:127) ~[na:1.8.0_311]
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:370) ~[na:1.8.0_311]
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:313) ~[na:1.8.0_311]
    at sun.security.ssl.TransportContext.fatal(TransportContext.java:308) ~[na:1.8.0_311]
    at sun.security.ssl.SSLTransport.decode(SSLTransport.java:141) ~[na:1.8.0_311]
    at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1290) ~[na:1.8.0_311]
    at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1199) ~[na:1.8.0_311]
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:401) ~[na:1.8.0_311]
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:373) ~[na:1.8.0_311]
    at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:379) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:337) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:209) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.kt:32) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.kt:95) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.kt:83) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.kt:76) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:109) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.connection.RealCall.getResponseWithInterceptorChain$okhttp(RealCall.kt:201) ~[okhttp-4.9.1.jar!/:na]
    at okhttp3.internal.connection.RealCall.execute(RealCall.kt:154) ~[okhttp-4.9.1.jar!/:na]
    at com.demo.service.impl.POServiceImpl.send(POServiceImpl.java:122) ~[classes!/:0.0.1-SNAPSHOT]
    at sun.reflect.GeneratedMethodAccessor82.invoke(Unknown Source) ~[na:na]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_311]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_311]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) [spring-aop-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198) [spring-aop-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) [spring-aop-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
    at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115) [spring-aop-5.2.5.RELEASE.jar!/:5.2.5.RELEASE]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_311]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_311]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_311]
    at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_311]
    Suppressed: java.net.SocketException: Connection reset by peer: socket write error
        at java.net.SocketOutputStream.socketWrite0(Native Method) ~[na:1.8.0_311]
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111) ~[na:1.8.0_311]
        at java.net.SocketOutputStream.write(SocketOutputStream.java:155) ~[na:1.8.0_311]
        at sun.security.ssl.SSLSocketOutputRecord.encodeAlert(SSLSocketOutputRecord.java:83) ~[na:1.8.0_311]
        at sun.security.ssl.TransportContext.fatal(TransportContext.java:401) ~[na:1.8.0_311]
        ... 36 common frames omitted
求证目标

想请大家帮忙分析下,出现Connection reset报错时,服务器端是否必然会接收到请求?
如果服务端必然会接收到请求,那么就有可能是日志被抹掉了导致对方告知我方并未接收到接口请求。
如果服务端不一定会接收到请求(报错时), 那么我想知道什么样的原因会导致此问题?

  • 写回答

0条回答 默认 最新

    报告相同问题?

    问题事件

    • 系统已结题 10月4日
    • 创建了问题 9月26日

    悬赏问题

    • ¥15 matlab中mjs用不了
    • ¥15 Ios抖音直播的时候如何添加自定义图片在直播间!
    • ¥60 riscv-pulpino总线上挂载axi从机
    • ¥15 ssh登录页面的问题
    • ¥50 关于在matlab上对曲柄摇杆机构上一点的运动学仿真
    • ¥15 jetson nano
    • ¥15 :app:debugCompileClasspath'.
    • ¥15 windows c++内嵌qt出现数据转换问题。
    • ¥15 stm32 串口通讯过程中的问题
    • ¥20 公众号如何实现点击超链接后自动发送文字