You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

HTTPS协议下写入日文PDF二进制数据触发ClosedChannelException求助

问题描述

将英文/日文PDF二进制数据写入HttpServletResponse OutputStream时,HTTP协议下所有PDF均能正常输出,但HTTPS协议下仅日文PDF会抛出ClosedChannelException,英文PDF不受影响。


相关代码与配置

Servlet代码

@Override
@TraceMonitor
@ErrorHandling
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    super.doGet(req, resp);
    try {
        if (req.getParameter("inputIdtoTable") != null && req.getParameter("inputIdtoTable").length() > 0) {
            TableEntity tablentity = ordrArrivalDao.getTableEntityFindById(req.getParameter("inputIdtoTable"));
            resp.reset();
            resp.setBufferSize(DEFAULT_BUFFER_SIZE);
            resp.setContentType("application/pdf;charset=UTF-8");
            resp.setHeader("Content-Length", String.valueOf(tablentity.getPdfData().length));
            resp.setHeader("Content-disposition", "inline; filename=" + tablentity.getPdfFileName() + ".pdf");
            resp.getOutputStream().write(tablentity.getPdfData());
            resp.flushBuffer();
            resp.getOutputStream().close();
        }

    } catch (Exception e) {
        e.getStackTrace();
    } finally {

    }
}

web.xml中的Servlet配置

<servlet>
    <servlet-name>MyModelClass</servlet-name>
    <servlet-class>com.x.xx.y.model.MyModelClass</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>MyModelClass</servlet-name>
    <url-pattern>/servletName/*</url-pattern>
</servlet-mapping>

触发的异常(仅HTTPS协议下的日文PDF会出现)

java.nio.channels.ClosedChannelException

解决方案
  • 修复文件名编码问题:日文文件名未编码直接写入响应头,HTTPS下会导致头信息解析异常,触发连接提前关闭。需用URLEncoder编码文件名并兼容浏览器:

    String encodedFileName = URLEncoder.encode(tablentity.getPdfFileName(), "UTF-8").replace("+", "%20");
    resp.setHeader("Content-disposition", "inline; filename=\"" + encodedFileName + ".pdf\"");
    
  • 调整流操作逻辑:不要手动调用getOutputStream().close(),flushBuffer()后容器会自动处理流关闭,手动关闭会导致容器后续操作时通道已关闭,直接移除该行代码。

  • 移除无效的字符编码配置:PDF是二进制文件,无需设置charset=UTF-8,修改ContentType为:

    resp.setContentType("application/pdf");
    
  • 验证Content-Length准确性:若tablentity.getPdfData().length与实际二进制数据长度不匹配,HTTPS加密传输时会触发连接中断。无法确保长度准确时,可直接去掉Content-Length头,让容器自动使用分块传输。

  • 移除super.doGet()调用:父类doGet可能已写入部分响应内容,干扰后续输出,直接删除super.doGet(req, resp);。


修改后的Servlet代码示例

@Override
@TraceMonitor
@ErrorHandling
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    try {
        String inputId = req.getParameter("inputIdtoTable");
        if (inputId != null && !inputId.isEmpty()) {
            TableEntity tablentity = ordrArrivalDao.getTableEntityFindById(inputId);
            
            resp.reset();
            resp.setContentType("application/pdf");
            
            String encodedFileName = URLEncoder.encode(tablentity.getPdfFileName(), "UTF-8").replace("+", "%20");
            resp.setHeader("Content-disposition", "inline; filename=\"" + encodedFileName + ".pdf\"");
            
            OutputStream out = resp.getOutputStream();
            out.write(tablentity.getPdfData());
            out.flush();
        }
    } catch (Exception e) {
        e.printStackTrace();
        resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "PDF响应生成失败");
    }
}

内容的提问来源于stack exchange,提问作者Ashok B

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 13:15:29