附件的 HTTP 响应标头内容处置

Posted

技术标签:

【中文标题】附件的 HTTP 响应标头内容处置【英文标题】:HTTP response header content disposition for attachments 【发布时间】:2011-07-13 19:59:40 【问题描述】:

背景

将 XML 文档写入浏览器的响应流,并使浏览器显示“另存为”对话框。

问题

考虑以下download() 方法:

  HttpServletResponse response = getResponse();

  BufferedWriter bw = new BufferedWriter( new OutputStreamWriter(
      response.getOutputStream() ) );

  String filename = "domain.xml";
  String mimeType = new MimetypesFileTypeMap().getContentType( filename );

  // Prints "application/octet-stream"
  System.out.println( "mimeType: " + mimeType );

  // response.setContentType( "text/xml;charset=UTF-8" );
  response.setContentType( mimeType );
  response.setHeader( "Content-Disposition", "attachment;filename="
      + filename );

  bw.write( getDomainDocument() );
  bw.flush();
  bw.close();

在 Firefox 中,XML 内容显示在浏览器窗口中。在 IE 7 中,不显示 XML 内容——您必须查看文档源。这两种情况都不是我们想要的结果。

网页对按钮使用以下代码:

    <a4j:commandButton action="#domainContent.download" value="Create Domain" reRender="error" />

生成的 XML&lt;?xml version="1.0"?&gt; 开头,而是 XML 内容类似于:

<schema xmlns="http://www.jaspersoft.com/2007/SL/XMLSchema" version="1.0">
  <items>
    <item description="EDT Class Code" descriptionId="" label="EDT Class Code" labelId="" resourceId="as_pay_payrolldeduction.edtclass"/>
  </items>
  <resources>
    <jdbcTable datasourceId="JNDI" id="as_pay_payrolldeduction" tableName="as_pay.payrolldeduction">
      <fieldList>
        <field id="payamount" type="java.math.BigDecimal"/>
      </fieldList>
    </jdbcTable>
  </resources>
</schema>

更新 #1

注意以下代码行:

response.setHeader( "Content-Disposition", "attachment;filename=" + filename );

更新 #2

使用&lt;a4j:commandButton ... /&gt; 是问题所在;一个普通的&lt;h:commandButton .../&gt; 按预期执行。使用&lt;h:commandBUtton .../&gt; 可以防止&lt;a4j:outputPanel .../&gt; 刷新任何错误消息。

相关Seam Message.

Mime 类型

以下 mime 类型不会触发“另存为”对话框:

"application/octet-stream" "text/xml" "text/plain"

问题

哪些更改会导致a4j:commandButton 触发“另存为”对话框,从而提示用户保存 XML 文件(作为domain.xml)?

谢谢。

【问题讨论】:

【参考方案1】:

不使用内联;也不是附件;只需使用

response.setContentType("text/xml");
response.setHeader( "Content-Disposition", "filename=" + filename );

response.setHeader( "Content-Disposition", "filename=\"" + filename + "\"" );

response.setHeader( "Content-Disposition", "filename=\"" + 
  filename.substring(0, filename.lastIndexOf('.')) + "\"");

【讨论】:

这一切看起来都很简洁合理,但为什么要避免“附件”呢?尽管 RFC 6266 建议“未知或未处理的处置类型应该由收件人以与“附件”相同的方式处理”,但“应该”与“必须”不同。 'attachment' 只是让这种技术更可靠...... 如果您在内容配置中错过了“附件”,Internet Explorer 11 将尝试使用奇怪的字符串在新选项卡中加载文档(例如 doc)【参考方案2】:

尝试将您的内容类型(媒体类型)更改为application/x-download,并将您的内容处置更改为:attachment;filename=" + fileName;

response.setContentType("application/x-download");
response.setHeader("Content-disposition", "attachment; filename=" + fileName);

【讨论】:

【参考方案3】:

问题

代码存在以下问题:

Ajax 调用 (&lt;a4j:commandButton .../&gt;) 不适用于附件。 必须先创建输出内容。 显示错误消息也不能使用基于Ajax的a4j标签。

解决方案

    &lt;a4j:commandButton .../&gt; 更改为&lt;h:commandButton .../&gt;。 更新源代码:
      bw.write( getDomainDocument() ); 更改为bw.write( document );。 将String document = getDomainDocument(); 添加到try/catch 的第一行。
    &lt;a4j:outputPanel.../&gt;(未显示)更改为&lt;h:messages showDetail="false"/&gt;

基本上,删除与commandButton 相关的所有 Ajax 工具。仍然可以显示错误消息并利用 RichFaces UI 样式。

参考文献

Using a commandButton in a jsf Page to download a file http://www.coderanch.com/t/483892/JSF/java/when-commandButton-commandLink http://seamframework.org/135584.lace

【讨论】:

【参考方案4】:

试试Content-Disposition 标头

Content-Disposition: attachment; filename=<file name.ext> 

【讨论】:

听起来这是一个 Eclipse 问题。使用嵌入式浏览器?也许它有一些禁用下载弹出窗口的配置。【参考方案5】:

这与 MIME 类型无关,而是 Content-Disposition 标头,应该是这样的:

Content-Disposition: attachment; filename=genome.jpeg;

确保它实际上正确地传递给客户端(没有被服务器、代理或其他东西过滤)。您也可以尝试更改写入标题的顺序并在获取输出流之前设置它们。

【讨论】:

以上是关于附件的 HTTP 响应标头内容处置的主要内容,如果未能解决你的问题,请参考以下文章

j2me - 内容处置附件;文件名 - 如何获得它?

Azure Blob Storage V2 不再提供内容处置标头

Android 浏览器/webview 错误?内容处置:附件;文件名="xyz.txt"

如何读取在 http 响应中发送的 GZip 内容

无法添加附件

将 HTTP 文件附件读取为字符串