【问题标题】:Reading and displaying encrypted PDF-file in JSF在 JSF 中读取和显示加密的 PDF 文件
【发布时间】:2014-04-02 05:51:36
【问题描述】:

根据BalusC's homepage,我实现了函数downloadPDF(),它从文件系统中读取一个PDF文件并在浏览器中显示。此功能按预期工作。

此外,我有一个类EncryptionService,它可以让我加密和/或解密给定的文件。这也可以按预期工作。

不幸的是,似乎无法读取 PDF 文件、对其进行解密并在浏览器中显示。它以浏览器尝试一遍又一遍地加载文件而不显示任何内容而结束。

下面的代码显示了我对 BalusC 的 PDF 处理程序的简单修改。

public void showDocument(String path, boolean decrypt) throws IOException, InvalidKeyException {

    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();

    File file = new File(path);
    BufferedInputStream input = null;
    BufferedOutputStream output = null;

    try {
        if(!decrypt)
            input = new BufferedInputStream(new FileInputStream(file), DEFAULT_BUFFER_SIZE);
        else {
            // update MessageDigets, return Key
            cipher.init(Cipher.DECRYPT_MODE, genKey(passphrase));

            input = new BufferedInputStream(new CipherInputStream(new FileInputStream(file), cipher), DEFAULT_BUFFER_SIZE);
        }

        response.reset();
        response.setHeader("Content-Type", "application/pdf");
        response.setHeader("Content-Length", String.valueOf(file.length()));
        response.setHeader("Content-Disposition", "inline; filename=\"" + path + "\"");

        output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);

        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
        int length;
        while ((length = input.read(buffer)) > 0) {
            output.write(buffer, 0, length);
        }

        output.flush();
    } finally {
        try {
            input.close();
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    facesContext.responseComplete();
}

【问题讨论】:

  • 具体在什么时候发生循环? showDocument 是否完成执行?什么被发送回浏览器?在浏览器的网络选项卡中查看响应代码、标头和响应正文包
  • @kolossus, showDocument 确实完成了。当我在新选项卡中加载某些内容时,网络选项卡不显示任何内容。尝试在同一选项卡中加载时,它会显示 system.jsf(当前站点)。几秒钟后,这会导致错误net::ERR_CONTENT_LENGTH_MISMATCH
  • 这样你就可以了:你设置为Content-Length != 现实中通过网络传输的内容。
  • 你能告诉我这个值应该是多少吗?如果文件的长度,我真的不明白内容长度应该是多少。
  • 一方面,加密可能会增加文件的大小,而解密会逆转效果。话虽如此,您通常不希望对文件的两个变体重用相同的变量:缓存和一般 I/O 不可靠性可能会导致问题。因此,为了进行实验,对 pdf 的加密和解密形式使用单独的 Files;不要为两者重复使用file

标签: java jsf pdf encryption primefaces


【解决方案1】:

发生了什么

就像控制台错误所说的那样

net::ERR_CONTENT_LENGTH_MISMATCH

这表示响应正文中返回的内容的实际大小与响应的Content-Length 标头中指示的大小不匹配。

为什么会发生

差异的原因分布在 2 个因素上:

  • 加密通常会增加加密内容的大小。加密过程需要通过密码来混淆内容,这通常意味着投入会使内容无法使用的东西。另一方面,解密会将内容恢复为原始大小

  • 浏览器容易缓存。如果您提供不同文件的次数足够多(使用相同的文件名),您的浏览器很可能只是确定它是同一个文件具有相同的内容,并且只提供该文件的缓存版本。在您的情况下,您声明对加密文件的引用、访问该文件、对其进行解密,然后将解密的内容直接写回到加密版本的同一文件句柄中。

  • 基于磁盘的 I/O 并非 100% 与 RAM 或 CPU 同步。写入磁盘和从磁盘读取仍然会以 RAM 等待磁盘的形式产生开销。

修复

  • 为您的操作中涉及的每个文件生成一个随机/不同的文件名。这意味着加密内容的文件名和解密形式的单独文件名

  • 作为上述点的推论,打开不同的输出流到不同的文件,也使用不同的File访问变量。

相关:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    • 2021-09-24
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    相关资源
    最近更新 更多