Encountering org.apache.catalina.connector.ClientAbortException again: java.net.SocketException: Broken pipe (Write failed)…

On the “Payment Record” page of the Youfu merchant platform, the merchant operator clicks the “Download Settlement Voucher” button, and the system will return the receipt file of the transaction with the selected conditions to the browser page in the form of a zip package.

Because the program involves complex calculations, library reading, network, and disk IO, it takes a long time. In order to prevent repeated requests, today, I used redis distributed lock to prevent repeated submission control.

@RequestMapping(value = "/downLoadBill")
public void downLoadBill(HttpServletRequest request, HttpServletResponse response) throws Exception {
    UserVO userVO=(UserVO) request.getSession().getAttribute("userVO");
    log.info("==MERCHANT==Settlement voucher download, execution starts==enterprise id={}", userVO.getMERID());
    response.setCharacterEncoding(Constant.CHARSET);

    String lockKey="downLoadBill:" + userVO.getMERID();
    String lockValue = UUID.randomUUID().toString();
    boolean getLock = JedisUtils.tryGetDistributedLock(lockKey, lockValue,15000);
    if (!getLock) {
        log.info("Settlement voucher is being downloaded, please do not submit it again");
        response.getWriter().write("You seem to have made repeated submission operations. Please re-initiate the request. Due to the large amount of data, we hope you will wait patiently for the system response!");
        return;
    }
    
    ....
    OutputStream responseStream = new BufferedOutputStream(response.getOutputStream());
    response.setContentType("application/octet-stream");
    response.setHeader("Content-Disposition", "attachment;filename=" + new String(file.getName().getBytes("UTF-8"),"ISO-8859-1"));
    responseStream.write(buffer);
    responseStream.flush();
    
    ....
} 

Then, when the merchant operator clicks repeatedly on the page, the page interaction is as follows:

Page interaction is OK, but by monitoring the running log, I found that the program reported an exception: org.apache.catalina.connector.ClientAbortException: java.net.SocketException: Disconnected pipe (Write failed)
Similarly, looking at the browser’s network requests, we also found that the interface was called twice by repeated clicks. However, the first time went viral, and the second time responded normally.

The following is the code to write the byte stream to the response

 try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file.getPath()));
         OutputStream responseStream = new BufferedOutputStream(response.getOutputStream())) {
        //Download the file as a stream.
        byte[] buffer = new byte[fis.available()];
        fis.read(buffer);
        fis.close();
        // Clear response
        response.reset();

        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment;filename=" + new String(file.getName().getBytes("UTF-8"), "ISO-8859-1"));
     <strong> responseStream.write(buffer);</strong>
        responseStream.flush();
        responseStream.close();
<strong> } </strong><strong>catch</strong><strong> (IOException ex) {<!-- --></strong>
        ex.printStackTrace();
    }

The following is the log of the two requests:

2021-06-23 18:05:46.966 [INFO] [downLoadBill_1624442477031S903] [com.yft.controller.SettleController:2125] ==MERCHANT==Settlement voucher download, execution starts==Enterprise id=89900000222116027420
2021-06-23 18:05:47.001(Timestamp), com.yft.service.impl.TPlatOrderServiceImpl(String), selectPlatOrderPage(String), selectPlatOrderPage(String), 192.168.40.69(String)
2021-06-23 18:05:47.008 [INFO] [downLoadBill_1624442477031S903] [com.yft.controller.SettleController:2199] ====MERCHANT== Settlement voucher download, there are {}==19 settlement vouchers to be downloaded.
2021-06-23 18:05:47.013 [INFO] [downLoadBill_1624442477031S903] [com.yft.controller.SettleController:2202] ====MERCHANT==Settlement voucher download, define temporary folder==/home/zipTempPath/89900000222116027420 /20210623/
2021-06-23 18: 05: 47.014 [Info] [DownloadBill_1624442477031S903] [com.yft.controller.SettterController: 2208] === Merchant == Credit download vouchers download. Platorder.orderid: 2021061014474300562655, obtain a settlement certificate ==/home/zipTempPath/89900000222116027420/20210623/20210610_2021061014474300562655.pdf
2021-06-23 18:05:47.043 [INFO] [downLoadBill_1624442477021S655] [com.yft.controller.SettleController:2125] ==MERCHANT==Settlement voucher download, execution starts==Enterprise id=89900000222116027420
2021-06-23 18:05:47.044 [INFO] [downLoadBill_1624442477021S655] [com.yft.controller.SettleController:2132] The settlement voucher is being downloaded, please do not submit it again.
2021-06-23 18: 05: 47.109 [Info] [DOWNLOADBILL_1624442477031S903] [com.yft.controller.SettLeController: 2208] === Merchant == Credit download vouchers download, circular processing order order ordering order Platorder.orderid: 2021061014474300562654, obtain a settlement certificate ==/home/zipTempPath/89900000222116027420/20210623/20210610_2021061014474300562654.pdf
2021-06-23 18: 05: 47.117 [Info] [DOWNLOADBILL_1624442477031S903] [com.yft.controller.SettLeController: 2208] === Merchant == Credit document download, circular processing order order ordering order Platorder.orderid: 2021061014093100562651, obtain a settlement certificate ==/home/zipTempPath/89900000222116027420/20210623/20210610_2021061014093100562651.pdf
2021-06-23 18:05:47.124 [INFO] [downLoadBill_1624442477031S903] [com.yft.controller.SettleController:2208]
====MERCHANT== Download the settlement voucher, process the order platOrder.orderid:2021060718400100562574 in a loop, and obtain the settlement voucher ==/home/zipTempPath/89900000222116027420/20210623/20210607_2021060718400100562574. pdf
....
2021-06-23 18: 05: 47.649 [Info] [DOWNLOADBILL_1624442477031S903] [com.yft.controller.SettLeController: 2208] === Merchant == settlement vouchers download, circular processing order order orders Platorder.orderid: 2021060718380400562573, get a settlement certificate ==/home/zipTempPath/89900000222116027420/20210623/20210607_2021060718380400562573.pdf
2021-06-23 18:05:47.656 [INFO] [downLoadBill_1624442477031S903] [com.yft.controller.SettleController:2225] ====MERCHANT==Settlement voucher download, define zip file path==20210623180547.zip
org.apache.catalina.connector.ClientAbortException: java.net.SocketException: Broken pipe (Write failed)
    at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:410)
    at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:352)
    at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:435)
    at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:423)
    at org.apache.catalina.connector.CoyoteOutputStream.write(CoyoteOutputStream.java:91)
    at org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper$SaveContextServletOutputStream.write(SaveContextOnUpdateOrErrorResponseWrapper.java:457)
    at java.io.BufferedOutputStream.write(BufferedOutputStream.java:122)
    at java.io.FilterOutputStream.write(FilterOutputStream.java:97)
<strong> at com.yft.util.DownloadFileUtil.downloadFile(DownloadFileUtil.java:</strong><strong>99</strong><strong>)</strong>
    at com.yft.controller.SettleController.downLoadBill(SettleController.java:2236)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    . . .
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
    Suppressed: org.apache.catalina.connector.ClientAbortException: java.net.SocketException: Broken pipe (Write failed)
        at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:370)
        at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:334)
        at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:101)
        at org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper$SaveContextServletOutputStream.flush(SaveContextOnUpdateOrErrorResponseWrapper.java:376)
        at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:141)
        at java.io.FilterOutputStream.close(FilterOutputStream.java:158)
<strong> at com.yft.util.DownloadFileUtil.downloadFile(DownloadFileUtil.java:</strong><strong>105</strong><strong>)</strong>
        ... 77 more
    Caused by: java.net.SocketException: Broken pipe (Write failed)
        at java.net.SocketOutputStream.socketWrite0(Native Method)
        at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
        at java.net.SocketOutputStream.write(SocketOutputStream.java:155)
        at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:216)
        at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:442)
        at org.apache.coyote.http11.InternalOutputBuffer.flush(InternalOutputBuffer.java:120)
        at org.apache.coyote.http11.AbstractHttp11Processor.action(AbstractHttp11Processor.java:849)
        at org.apache.coyote.Response.action(Response.java:171)
        at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:366)
        ... 83 more
Caused by: java.net.SocketException: Broken pipe (Write failed)
    at java.net.SocketOutputStream.socketWrite0(Native Method)
    at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
    at java.net.SocketOutputStream.write(SocketOutputStream.java:155)
    at org.apache.coyote.http11.InternalOutputBuffer.realWriteBytes(InternalOutputBuffer.java:216)
    at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:442)
    at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:347)
    at org.apache.coyote.http11.InternalOutputBuffer$OutputStreamOutputBuffer.doWrite(InternalOutputBuffer.java:239)
    at org.apache.coyote.http11.filters.ChunkedOutputFilter.doWrite(ChunkedOutputFilter.java:119)
    at org.apache.coyote.http11.AbstractOutputBuffer.doWrite(AbstractOutputBuffer.java:192)
    at org.apache.coyote.Response.doWrite(Response.java:495)
    at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:405)
    ... 85 more
2021-06-23 18:05:48.194 [INFO] [downLoadBill_1624442477031S903] [com.yft.qrcodeUtil.FileOperateUtil:54] Execute linux command to delete the directory, linux cmd=/bin/rm -rf /home/zipTempPath/89900000222116027 420/20210623 /

The following is a screenshot of the network request in the F12 debugger window of Google Chrome:

So, why does the “ClientAbortException: java.net.SocketException: Broken Pipe (Write failed)” exception occur?

The reason is: when the browser submits repeatedly, because it is a synchronous request, when the second request arrives, the browser has already closed the first request. At this time, the server’s processing of the first request has not yet ended (the thread is still in the RUNNABLE state). When data is written to the response stream, the client connection has been disconnected, so a “disconnected pipe (Write)” appears. failed)” exception, because it is a response exception, the exception type is SocketException.

As shown below:

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Java Skill TreeHomepageOverview 136778 people are learning the system