我想模拟文件上传,而不是使用用户的文件输入。文件内容将从字符串动态生成。
这种方法可行吗? 有人以前做过吗?是否有示例或理论支持?
需要澄清的是,我知道如何使用 AJAX 技术通过隐藏 iframe 等方式上传文件 - 问题是上传不在表单中的文件。
我正在使用 ExtJS,但 jQuery 也可以,因为 ExtJS 可以与其集成 (ext-jquery-base)。
我想模拟文件上传,而不是使用用户的文件输入。文件内容将从字符串动态生成。
这种方法可行吗? 有人以前做过吗?是否有示例或理论支持?
需要澄清的是,我知道如何使用 AJAX 技术通过隐藏 iframe 等方式上传文件 - 问题是上传不在表单中的文件。
我正在使用 ExtJS,但 jQuery 也可以,因为 ExtJS 可以与其集成 (ext-jquery-base)。
FormData
对象,该对象是File API的一部分。const formData = new FormData();
const blob = new Blob(['Lorem ipsum'], { type: 'plain/text' });
formData.append('file', blob, 'readme.txt');
const request = new XMLHttpRequest();
request.open('POST', 'http://example.org/upload');
request.send(formData);
所有当前浏览器(IE10+)都支持文件API
为什么不直接使用带有POST的XMLHttpRequest()
?
function beginQuoteFileUnquoteUpload(data)
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://www.mysite.com/myuploadhandler.php", true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function ()
{
if (xhr.readyState == 4 && xhr.status == 200)
alert("File uploaded!");
}
xhr.send("filedata="+encodeURIComponent(data));
}
服务器上的处理程序只是将文件数据写入文件。
编辑
文件上传仍然是一个HTTP POST请求,但内容类型不同。您可以使用此内容类型并使用分界符将内容分开:
function beginQuoteFileUnquoteUpload(data)
{
// Define a boundary, I stole this from IE but you can use any string AFAIK
var boundary = "---------------------------7da24f2e50046";
var xhr = new XMLHttpRequest();
var body = '--' + boundary + '\r\n'
// Parameter name is "file" and local filename is "temp.txt"
+ 'Content-Disposition: form-data; name="file";'
+ 'filename="temp.txt"\r\n'
// Add the file's mime-type
+ 'Content-type: plain/text\r\n\r\n'
+ data + '\r\n'
+ boundary + '--';
xhr.open("POST", "http://www.mysite.com/myuploadhandler.php", true);
xhr.setRequestHeader(
"Content-type", "multipart/form-data; boundary="+boundary
);
xhr.onreadystatechange = function ()
{
if (xhr.readyState == 4 && xhr.status == 200)
alert("File uploaded!");
}
xhr.send(body);
}
如果您想发送附加数据,则只需使用边界分隔每个部分,并为每个部分描述content-disposition和content-type标头。每个标头由换行符分隔,正文则由额外的换行符与标头分隔。自然地,以这种方式上传二进制数据会更加困难 :-)分享最终结果,它能够正常工作-并且具有添加/删除参数的干净方式,而无需硬编码任何内容。
var boundary = '-----------------------------' +
Math.floor(Math.random() * Math.pow(10, 8));
/* Parameters go here */
var params = {
file: {
type: 'text/plain',
filename: Path.utils.basename(currentTab.id),
content: GET_CONTENT() /* File content goes here */
},
action: 'upload',
overwrite: 'true',
destination: '/'
};
var content = [];
for(var i in params) {
content.push('--' + boundary);
var mimeHeader = 'Content-Disposition: form-data; name="'+i+'"; ';
if(params[i].filename)
mimeHeader += 'filename="'+ params[i].filename +'";';
content.push(mimeHeader);
if(params[i].type)
content.push('Content-Type: ' + params[i].type);
content.push('');
content.push(params[i].content || params[i]);
};
/* Use your favorite toolkit here */
/* it should still work if you can control headers and POST raw data */
Ext.Ajax.request({
method: 'POST',
url: 'www.example.com/upload.php',
jsonData: content.join('\r\n'),
headers: {
'Content-Type': 'multipart/form-data; boundary=' + boundary,
'Content-Length': content.length
}
});
该方案已在所有现代浏览器上进行了测试,包括但不限于:
for in
?它似乎准备处理多个文件,但第二个文件在对象中如何命名?action
、overwrite
和 destination
在哪里使用?它们如何不破坏 for in
中的代码? - Mariano Desanzefor( in )
的原因是为了从描述对象中获取键。代码将检测是否在嵌套对象上设置了 filename
(描述要上传的文件)。其他参数(overwrite
、action
、destination
)只是作为表单传递的额外参数。 - LiraNuna-----------------------------
感到神奇,但 MIME 规范(参见 RFC 1341,第7.2.1节)唯一的要求是边界以--
开头,后跟有效令牌(参见 RFC 1341 第4节)。希望这能帮助其他人了解他们的自由 :-) - JWL使用jQuery模拟“虚假”文件上传的简单方法:
var fd = new FormData();
var file = new Blob(['file contents'], {type: 'plain/text'});
fd.append('formFieldName', file, 'fileName.txt');
$.ajax({
url: 'http://example.com/yourAddress',
method: 'post',
data: fd,
processData: false, //this...
contentType: false //and this is for formData type
});
我刚用Firefox的TamperData插件捕获了这个POST_DATA字符串。我提交了一个带有一个名为“myfile”的type="file"
字段和一个名称为“btn-submit”的提交按钮,值为“上传”的表单。上传文件的内容如下:
Line One
Line Two
Line Three
所以这里是POST_DATA字符串:
-----------------------------192642264827446\r\n
Content-Disposition: form-data; \n
name="myfile"; filename="local-file-name.txt"\r\n
Content-Type: text/plain\r\n
\r\n
Line \n
One\r\n
Line Two\r\n
Line Three\r\n
\r\n
-----------------------------192642264827446\n
\r\n
Content-Disposition: form-data; name="btn-submit"\r\n
\r\n
Upload\n
\r\n
-----------------------------192642264827446--\r\n
我不确定这个数字的含义(192642264827446),但是找出来应该不难。
multipart/form-data
标头,边界将跟随它。结尾处的随机数是为了避免与正在发送的数据发生冲突。 - Andy Ehttps://dev59.com/FHI95IYBdhLWcg3wsQFm#2198524对我很有帮助,只需要在有效载荷中的最后一个boundary
前添加额外的'--'
即可:
var body = '--' + boundary + '\r\n'
// Parameter name is "file" and local filename is "temp.txt"
+ 'Content-Disposition: form-data; name="file";'
+ 'filename="temp.txt"\r\n'
// Add the file's mime-type
+ 'Content-type: plain/text\r\n\r\n'
+ data + '\r\n'
+ '--' + boundary + '--';