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
相关产品推荐
相关产品推荐

