我在服务器端有一个Struts2动作用于文件下载 .
<action name="download" class="com.xxx.DownAction">
<result name="success" type="stream">
<param name="contentType">text/plain</param>
<param name="inputName">imageStream</param>
<param name="contentDisposition">attachment;filename={fileName}</param>
<param name="bufferSize">1024</param>
</result>
</action>
但是当我使用jQuery调用动作时:
$.post(
"/download.action",{
para1:value1,
para2:value2
....
},function(data){
console.info(data);
}
);
在Firebug中,我看到使用 Binary stream 检索数据 . 我想知道如何打开用户可以在本地保存文件的 file downloading window ?
16 回答
Bluish对此完全正确,你可以't do it through Ajax because JavaScript cannot save files directly to a user'的电脑(出于安全考虑) . 不幸的是,将主窗口的URL指向文件下载意味着您几乎无法控制文件下载时的用户体验 .
我创建了jQuery File Download,它允许使用OnSuccess和OnFailure回调完成文件下载,以提供更好的用户体验 . 看看我的blog post关于插件解决的常见问题以及使用它的一些方法以及demo of jQuery File Download in action . 这是source
这是一个简单的用例演示,使用带有promises的插件source . demo page还包括许多其他的'better UX'示例 .
根据您需要支持的浏览器,您可以使用https://github.com/eligrey/FileSaver.js/,它允许比jQuery文件下载使用的IFRAME方法更明确的控制 .
没有人发布这个@Pekka's solution ...所以我会发布它 . 它可以帮助某人 .
您不能也不需要通过Ajax执行此操作 . 只是用
You can with HTML5
注意:返回的文件数据必须是base64编码的,因为你不能JSON编码二进制数据
在我的
AJAX
响应中,我有一个如下所示的数据结构:这意味着我可以通过AJAX保存文件
函数base64ToBlob取自here,必须按照此函数使用
如果您的服务器正在转储要保存的filedata,这很好 . 但是,我还没有弄清楚如何实现HTML4后备
1. Framework agnostic: Servlet downloading file as attachment
2. Struts2 Framework: Action downloading file as attachment
最好将指向OGNL的
<s:a>
标记用于使用<s:url>
标记创建的URL:在上述情况下,您 need 将Content-Disposition标头写入响应,指定该文件需要下载(
attachment
)而不是由浏览器打开(inline
) . 您 need 也指定了内容类型,您可能想要添加文件名和长度(以帮助浏览器绘制真实的进度条) .例如,下载ZIP时:
使用Struts2(除非您使用Action作为Servlet,例如hack for direct streaming),您不需要直接向响应写入任何内容;只需使用Stream result type并在struts.xml中配置它就可以了:EXAMPLE
3. Framework agnostic (/ Struts2 framework): Servlet(/Action) opening file inside the browser
如果要在浏览器中打开文件而不是下载它,则必须将Content-disposition设置为inline,但目标不能是当前窗口位置;你必须定位一个由javascript创建的新窗口,页面中的
<iframe>
,或者使用"discussed" target = "_blank"在运行中创建的新窗口:我创建了一个小功能作为解决方案解决方案(受@JohnCulviner插件启发):
点击事件演示:
好的,基于ndpu的代码继承了ajax_download的改进版(我认为); -
像这样使用这个; -
params作为正确的post params发送,好像来自输入而不是像前面的例子那样作为json编码的字符串 .
CAVEAT:对这些形式的可变注射潜力持谨慎态度 . 可能有一种更安全的方法来编码这些变量 . 或者考虑逃避它们 .
使浏览器下载文件的简单方法是发出如下请求:
这将打开浏览器下载弹出窗口 .
我遇到了同样的问题并成功解决了它 . 我的用例是这样的 .
“将JSON数据发布到服务器并接收excel文件 . 该excel文件由服务器创建并作为对客户端的响应返回 . 在浏览器中将该响应下载为具有自定义名称的文件”
上面的代码片段正在做以下事情
使用XMLHttpRequest将数组作为JSON发布到服务器 .
在将内容作为blob(二进制)获取后,我们创建了一个可下载的URL并将其附加到不可见的"a"链接然后单击它 . 我在这里做了一个POST请求 . 相反,你也可以进行简单的GET . 我们无法通过Ajax下载文件,必须使用XMLHttpRequest .
在这里,我们需要在服务器端仔细设置一些东西 . 我在Python Django HttpResponse中设置了几个 Headers . 如果使用其他编程语言,则需要相应地设置它们 .
由于我在这里下载xls(excel),我将contentType调整为高于1 . 您需要根据文件类型进行设置 . 您可以使用此技术下载任何类型的文件 .
这是我做的,纯粹的javascript和HTML . 没有测试它,但这应该适用于所有浏览器 .
在上面的答案中添加更多内容以下载文件
下面是一些生成字节数组的java spring代码
现在使用FileSaver.js的javascript代码,可以下载带有以下代码的文件
以上将下载文件
在Rails中,我这样做:
诀窍是window.location部分 . 控制器的方法如下:
好的,这是使用MVC时的工作代码,你从控制器获取文件
假设你有你的字节数组声明和填充,你唯一需要做的就是使用File函数(使用System.Web.Mvc)
然后,在同一个控制器中,添加2个函数
然后你就可以打电话给你的控制器下载并获得“成功”或“失败”的回调
如果你想使用jQuery文件下载,请注意这个IE . 您需要重置响应,否则将无法下载
您的操作可以实现
ServletResponseAware
来访问getServletResponse()
我找到了一个修复,虽然它实际上并没有使用ajax,但它确实允许你使用javascript调用来请求下载,然后在下载实际开始时获得回调 . 我发现这有用,如果链接运行服务器端脚本,在发送之前需要一点点来编写文件 . 因此,您可以提醒他们正在处理,然后当它最终发送文件时删除该处理通知 . 这就是为什么我想尝试通过ajax加载文件开始,以便我可以在请求文件时发生事件,而在实际开始下载时发生另一个事件 .
首页上的js
iframe
那么另一个文件:
我认为有一种方法可以使用js读取数据,因此不需要php . 但我不知道它和我正在使用的服务器支持PHP所以这对我有用 . 以为我会分享它,以防它帮助任何人 .
可以肯定的是,你无法通过Ajax调用来实现 .
但是,有一种解决方法 .
脚步 :
如果您使用form.submit()下载文件,您可以做的是:
从客户端到服务器创建ajax调用,并将文件流存储在会话中 .
在从服务器返回"success"时,调用form.submit()以仅流式传输存储在会话中的文件流 .
如果你想在make.submit()之后决定是否需要下载文件,这很有用,例如:在form.submit()上可能存在一种情况,在服务器端发生异常而是崩溃时,您可能需要在客户端显示自定义消息,在这种情况下,此实现可能会有所帮助 .