ajax Extjs 4(下面有 3.4 的代码)下载从 post 请求返回的文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11782856/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Extjs 4 (with a code for 3.4 below) downloading a file returned from a post request
提问by Bbb
I have seen questions slightly related to this, but none that answer my problem. I have set up an Ext.Ajax.request as follows:
我见过与此稍微相关的问题,但没有一个能回答我的问题。我已经设置了一个 Ext.Ajax.request 如下:
var paramsStringVar = 'param1=1¶m2=two¶m3=something¶m4=etc';
Ext.Ajax.request({
url: '/cgi-bin/url.pl',
method:'POST',
params:paramsStringVar,
timeout:120000,
success: function(response, opts){
var objhtml = response.responseText; //content returned from server side
console.log(objhtml);
}
});
This request retrieves the appropriate content from the backend. One parameter is outputType, which can take values {html, excel, csv}. When returning html to display I am able to handle and display it correctly. Now on to the problem...
此请求从后端检索适当的内容。一个参数是 outputType,它可以取值 {html, excel, csv}。当返回 html 显示时,我能够正确处理和显示它。现在来解决这个问题...
When I set the outputType parameter to csv or excel, I get back the appropriate content as csv or tsv(excel) as requested. BUT, I don't want the content, I want a prompt to download the file(csv or excel). How can I have the browser auto prompt the user to download the file instead of just retrieving the text content within extjs?
当我将 outputType 参数设置为 csv 或 excel 时,我会根据要求将适当的内容作为 csv 或 tsv(excel) 取回。但是,我不想要内容,我想要提示下载文件(csv 或 excel)。如何让浏览器自动提示用户下载文件,而不是仅仅检索 extjs 中的文本内容?
Version 4.07 so I can't use any 4.1 only features
版本 4.07 所以我不能使用任何 4.1 的功能
回答by Dmitry Pashkevich
There seems to be no bulletproof solution but there are several approaches I would try:
似乎没有防弹解决方案,但我会尝试几种方法:
1)Use an iframeinstead of real XHR to POST data to the server, e.g. <form action="/something" target="myiframe">where myiframeis the nameof your hidden iframe. That way your form would use the iframe (not your main window) to submit data to the configured URL. Your server should set response header as application/octet-stream(or some ither MIME type for binary data) so the browser triggers download. Otherwise (if html returned in your case) you can just retrieve iframe's body innerHTML and display it to the user in UI. While using an iframe (or a new window) instead of XHR doesn't sound like the best idea, this solution seems to be the most reliable so far (and with best browser support).
1)使用的iframe,而不是真正的XHR到POST数据到服务器,如<form action="/something" target="myiframe">这里myiframe是name您隐藏的iframe的。这样您的表单将使用 iframe(而不是您的主窗口)将数据提交到配置的 URL。您的服务器应将响应标头设置为application/octet-stream(或二进制数据的某种 MIME 类型),以便浏览器触发下载。否则(如果在您的情况下返回 html),您只需检索 iframe 的正文 innerHTML 并将其显示给用户界面中的用户。虽然使用 iframe(或新窗口)而不是 XHR 听起来不是最好的主意,但这个解决方案似乎是迄今为止最可靠的(并且具有最好的浏览器支持)。
Here is a slightly modified example from Ext.form.Basicdocs page:
这是Ext.form.Basic文档页面的一个稍微修改的示例:
Ext.create('Ext.form.Panel', {
title: 'Basic Form',
renderTo: Ext.getBody(),
width: 350,
// Any configuration items here will be automatically passed along to
// the Ext.form.Basic instance when it gets created.
// *THIS* makes the form use a standard submit mechanism, not XHR
/**/standardSubmit: true,
// URL to submit to
url: 'save-form.php',
items: [{
fieldLabel: 'Field',
xtype: 'textfield',
name: 'theField'
}],
buttons: [{
text: 'Submit',
handler: function() {
// The getForm() method returns the Ext.form.Basic instance:
var form = this.up('form').getForm();
if (form.isValid()) {
// Submit the Ajax request and handle the response
form.submit({
success: function(form, action) {
Ext.Msg.alert('Success', action.result.msg);
},
failure: function(form, action) {
Ext.Msg.alert('Failed', action.result.msg);
},
// You can put the name of your iframe here instead of _blank
// this parameter makes its way to Ext.form.Basic.doAction()
// and further leads to creation of StandardSubmit action instance
/**/ target: '_blank'
});
}
}
}]
});
There are two key parameters here (lines marked with /**/):
这里有两个关键参数(标有 的行/**/):
standardSubmit: trueconfig that you pass to your form will make it do a standard submit instead of XHR.- Passing a
targetparameter to the form's submitaction. This feature is not documented but you can see it being used in Ext.form.action.Submitsource code (all options that you pass to Ext.form.Basic.submit()method end up as parameters of Ext.form.action.* instance.
standardSubmit: true您传递给表单的配置将使其执行标准提交而不是 XHR。- 将
target参数传递给表单的提交操作。这个特性没有被记录,但是你可以看到它在Ext.form.action.Submit源代码中被使用(你传递给Ext.form.Basic.submit()方法的所有选项最终都作为 Ext.form.action 的参数。 * 实例。
In the example code I put target: '_blank'to demonstrate that it works right away (will create a new browser window). You can replace it with the name of your iframe later but I suggest that you first test how your form submits data to a regular new window and then develop logic that creates and processes an iframe. You will have to process the result inside iframe yourself, thought. It's not that difficult, see Ext.data.Connection.upload()implementation as an example of iframe processing.
在示例代码中,我target: '_blank'展示了它可以立即工作(将创建一个新的浏览器窗口)。您可以稍后用 iframe 的名称替换它,但我建议您首先测试表单如何将数据提交到常规新窗口,然后开发创建和处理 iframe 的逻辑。你必须自己在 iframe 中处理结果,想。没那么难,看Ext.data.Connection.upload()实现作为 iframe 处理的例子。
ExtJS actually already uses the iframetechnique for file uploads. See Ext.data.Connectionand Ext.form.field.Field.isFileUpload()for an idea of how it can work.
ExtJS 实际上已经使用了iframe文件上传技术。请参阅Ext.data.Connection和Ext.form.field.Field.isFileUpload()以了解其工作原理。
2)Suggested here: Using HTML5/Javascript to generate and save a file.
2)此处建议:使用 HTML5/Javascript 生成并保存文件。
If you don't want to go the iframe way, you can try generate data URIfrom response data and navigate to that URI triggering download:
如果您不想采用 iframe 方式,您可以尝试从响应数据生成数据 URI并导航到该 URI 触发下载:
content = "Hello world!";
uriContent = "data:application/octet-stream," + encodeURIComponent(content);
window.location.href = uriContent;
Again, mimetype is essential here. This worked for me, you should note, however, that browsers impose a size limit to data URIs (256Kb is a safe bet).
同样,mimetype 在这里是必不可少的。这对我有用,但是您应该注意,浏览器对数据 URI 施加了大小限制(256Kb 是一个安全的赌注)。
3)Another answer in the mentioned thread links to FileSaver.jslibrary the implements the (abandoned?) w3 spec. Usage and demo here. It uses [BlobBuilder] to generate a blob of binary data that is further used to initialize downloads using one of several methods. While this solution seems to work, it uses deprecated APIs and may not be future-proof.
3)上述线程中的另一个答案链接到FileSaver.js库,它实现了(被放弃的?)w3 规范。用法和演示在这里。它使用 [BlobBuilder] 生成二进制数据 blob,进一步用于使用多种方法之一初始化下载。尽管此解决方案似乎有效,但它使用了已弃用的 API,并且可能无法满足未来的需求。
回答by Bbb
Below is my solution. This is how I have it currently working. The response generates a download/open prompt, based on a response type of text/csv. Note that no iFrame or reference to an iframe are needed. I spent a lot of time hung up on the need for an iFrame, which actually broke my solution. An iFrame is not needed to generate a download prompt. What is needed is a request(submittal) similar to this one, along with a backend generating the appropriate csv with text/csv response header.
下面是我的解决方案。这就是我目前的工作方式。该响应基于 text/csv 的响应类型生成下载/打开提示。请注意,不需要 iFrame 或对 iframe 的引用。我花了很多时间挂断了对 iFrame 的需求,这实际上破坏了我的解决方案。生成下载提示不需要 iFrame。需要的是一个与此类似的请求(提交),以及一个生成带有 text/csv 响应标头的适当 csv 的后端。
var hiddenForm = Ext.create('Ext.form.Panel', {
title:'hiddenForm',
standardSubmit: true,
url: /cgi-bin/url.pl
timeout: 120000,
height:0,
width: 0,
hidden:true,
items:[
{xtype:'hiddenField', name:'field1', value:'field1Value'},
// additional fields
]
})
hiddenForm.getForm().submit()
The standardSubmit line is vital
standardSubmit 行很重要
回答by Xibalban
You don't need to create a form panel and make it hidden in your extjs file. We can add a html form and on click of button in extjs file we can submit the form using the url. This will work both in IE as well as chrome browsers. Below is my code i tried and its working fine,
您不需要创建表单面板并将其隐藏在您的 extjs 文件中。我们可以添加一个 html 表单,点击 extjs 文件中的按钮,我们可以使用 url 提交表单。这将适用于 IE 和 chrome 浏览器。下面是我试过的代码,它工作正常,
<form action="<%=fullURL%>/DownloadServlet.do" method="get" id="downloadForm" name="downloadForm" target="_self">
</form>
click:
{
fn: function()
{
document.getElementById('downloadForm').submit();
}
}
回答by luca76
To get it working on ExtJS 3.4:
要让它在 ExtJS 3.4 上运行:
var hiddenForm = new Ext.FormPanel({
id:'hiddenForm',
region: 'south',
method: 'POST',
url: "/cgi/test.wsgi",
height: 0,
standardSubmit: true,
hidden:true,
items:[
{xtype:'hidden', name:'p', value:p},
{xtype:'hidden', name:'g', value:g},
// ...
],
});
linkThis = new Ext.Button({
text: 'Download this CSV',
handler: function() {
hiddenForm.getForm().submit();
},
maxHeight: 30,
});
Remember that in order to make it working, you should put the hiddenForm in any container (i.e. in the same Ext.Window of the button), for example:
请记住,为了使其工作,您应该将 hiddenForm 放在任何容器中(即在按钮的同一个 Ext.Window 中),例如:
risultatiWindow = new Ext.Window({
title: 'CSV Export',
height: 400,
width: 500,
....
items: [...., hiddenForm]
});

