2

我有一个非常奇怪的问题,我找不到解决方案。

我有一个简单的测试 servlet,它在响应中流式传输一个小的 pdf 文件:

public class TestPdf extends HttpServlet implements Servlet {

    private static final long serialVersionUID = 1L;

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {

        File file = new File(getServletContext().getRealPath("/lorem.pdf"));

        response.setContentType("application/pdf");

        ServletOutputStream out = response.getOutputStream();

        InputStream in = new FileInputStream(file);

        byte[] bytes = new byte[10000];

        int count = -1;

        while ((count = in.read(bytes)) != -1) {
            out.write(bytes, 0, count);
        }

        in.close();

        out.flush();
        out.close();

    }

}

如果我用浏览器、curl、wget 调用 servlet url,一切都很好,但是当我用这样的简单 TCL 脚本调用它时:

#!/usr/bin/tclsh8.5

package require http;

set testUrl "http://localhost:8080/test/pdf"
set httpResponse [http::geturl "$testUrl" -channel stdout]

该文件的开头有一个“2000”字符串破坏了pdf。

该问题似乎与 Tomcat 或 JDK 版本无关,因为我能够在我的开发环境(Ubuntu 16.04)上使用 JDK 1.5.0_22 Tomcat 5.5.36 和 JDK 1.8.0_74 和 Tomcat 8.5.15 重现它。

4

2 回答 2

3

正如其他人指出的那样,您看到的是块的开头,即块包含的八位字节数。要从 Tcl 客户端处理此问题(而不是通过从 Tomcat POV 关闭分块传输编码),您需要省略以下-channel选项http::geturl

package require http;

set testUrl "http://localhost:8080/test/pdf"
set httpResponse [http::geturl "$testUrl"]
fconfigure stdout -translation binary; # turn off auto-encoding on the way out
puts -nonewline stdout [http::data $httpResponse]

这应该将分块的内容正确地变形为一件。-channel背景是,当我上次检查时,该选项无法处理分块内容。

于 2018-08-10T08:55:50.463 回答
0

我从未使用过 TCL,但这是使用通用文件下载 servlet 的方式:

public class DownloadServlet extends HttpServlet {
    private final int BUFFER_SIZE = 10000;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
      throws ServletException, IOException {

        String filename = "test.pdf";
        String pathToFile = "..../" + filename;

        resp.setContentType("application/pdf");
        resp.setHeader("Content-disposition", "attachment; filename=" + filename);

        try(InputStream in = req.getServletContext().getResourceAsStream(pathToFile);
          OutputStream out = resp.getOutputStream()) {

            byte[] buffer = new byte[BUFFER_SIZE];
            int numBytesRead;

            while ((numBytesRead = in.read(buffer)) > 0) {
                out.write(buffer, 0, numBytesRead);
            }
        }
    }
}

希望这段代码对你有所帮助。

于 2018-08-10T08:03:18.827 回答