【问题标题】:Additional "2000" String ([32 30 30 30] bytes) at the beginning of a file文件开头的附加“2000”字符串([32 30 30 30] 字节)
【发布时间】:2019-01-17 18:34:38
【问题描述】:

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

我有一个简单的测试 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 重现它.

【问题讨论】:

  • 没用过TCL,不就是http代码200加个0然后你的文件吗?
  • 感谢您的评论。我只是尝试将HTTP响应代码更改为201,但“2000”仍然相同。
  • 您是否尝试过使用您的 TCL 脚本访问“已知良好”的 URL(例如 stackoverflow.com/robots.txt)?这样您就可以确定问题是来自 Java 代码还是 TCL。
  • 好的,我尝试使用示例 PDF (unec.edu.az/application/uploads/2014/12/pdf-sample.pdf) 并且下载的文件是正确的,所以问题与 Java/Tomcat 相关...
  • servlet 是否可能使用分块传输编码,而您的脚本不支持这种情况?在分块传输编码中,数据以块的长度为前缀(在 ASCII 中编码为十六进制,因此 2000 表示块为 8192 字节)以块的形式发送,然后是 CRLF 序列,然后是 8192 字节的数据,然后是CRLF,然后是下一个块,等等。

标签: java tomcat servlets tcl activetcl


【解决方案1】:

我从未使用过 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);
            }
        }
    }
}

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

【讨论】:

    【解决方案2】:

    你看到的是一个块的开始,块包含的八位字节数,正如其他人指出的那样。要从 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 选项无法处理分块内容。

    【讨论】:

    • 与使用-channel 的不同之处在于,您的响应数据最终将作为Tcl 值在内存中作为额外的数据。你也可以省略stdoutputs(默认),这只是为了让你的脚本的连接更明显。
    • 现在我刷新了记忆:从 Tcl 8.6、http 2.8.0 开始,-channel 处理分块传输编码。您应该获得一个全新的 Tcl 安装。
    • 这是 2009 年发布的 8.6.0。所以,你真的应该更新了!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多