附件的 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不以 <?xml version="1.0"?>
开头,而是 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
使用<a4j:commandButton ... />
是问题所在;一个普通的<h:commandButton .../>
按预期执行。使用<h:commandBUtton .../>
可以防止<a4j:outputPanel .../>
刷新任何错误消息。
相关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 调用 (<a4j:commandButton .../>
) 不适用于附件。
必须先创建输出内容。
显示错误消息也不能使用基于Ajax的a4j
标签。
解决方案
-
将
<a4j:commandButton .../>
更改为<h:commandButton .../>
。
更新源代码:
-
将
bw.write( getDomainDocument() );
更改为bw.write( document );
。
将String document = getDomainDocument();
添加到try/catch
的第一行。
<a4j:outputPanel.../>
(未显示)更改为<h:messages showDetail="false"/>
。
基本上,删除与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 响应标头内容处置的主要内容,如果未能解决你的问题,请参考以下文章
Azure Blob Storage V2 不再提供内容处置标头