我遇到了通过ajax上传文件而没有单独的html表单的困难。 我的情况是这样的:
出于测试目的,我尝试创建一个像这样发送的虚拟zip文件(不获取textarea内容):
var zip = new JSZip();
zip.file("hello1.txt", "Hello First World\n");<br/>
zip.file("hello2.txt", "Hello Second World\n");<br/>
var content = zip.generate();
然后我使用Jquery ajax方法发送,如下所示:
$.post("the_url",
{
GradeRequest : {
submitter_id : "foobar",
evaluationset_id : 9,
mode : 1,
source_file : "a.cpp",
file: content
}
}
);
但是服务器上没有收到该文件。 我在How can I upload files asynchronously?中已阅读过问题,但所有解决方案都使用的是html格式。是否有任何解决方案不涉及任何HTML格式?
提前致谢。
在服务器端,我正在使用Yii PHP Framework:
$model = $this->model;
if ($model !== null && isset($_POST['GradeRequest'])) {
$model->setAttributes($_POST['GradeRequest']);
if ($model->validate()) {
if (isset($_FILES['GradeRequest']['tmp_name']['file']) && $_FILES['GradeRequest']['tmp_name']['file'] !== "") {
$model->file = file_get_contents($_FILES['GradeRequest']['tmp_name']['file']);
$model->source_file = $_FILES['GradeRequest']['name']['file'];
}
$this->setReply(true, "Ok");
$model->client_id = $this->clientId;
$model->request_id = $this->requestRecord->id;
$model->save();
} else {
$this->setReply(false, $model->getErrors());
}
}
作为一个概念证明,我创建了一个这样的表单版本,它可以工作(文件上传到服务器):
<form enctype="multipart/form-data" method="post" action="[the_url]>
EvaluationSet id: <input type="text" name="GradeRequest[evaluationset_id]" /><br />
<input type="hidden" name="GradeRequest[mode]" value="0" />
<input type="hidden" name="GradeRequest[submitter_id]" value="Someone" />
Source file : <input type="text" name="GradeRequest[source_file]" /><br />
File : <input type="file" name="GradeRequest[file]" /><br />
<input type="submit" />
答案 0 :(得分:3)
有FormData
对象可以帮助你(它是所谓的xmlHttpRequest
版本2的一部分):这是一个compatibility chart,带有一些链接的引用和示例。
这样,您就可以为POST表单添加键/值对,包括File
个对象,并通过send
的常用xmlHttpRequest
方法将其全部发送。
File
元素轻松检索 <input type="file">
个对象,甚至可以使用drag&amp;从桌面上删除。
如果您想将某个文件内容上传为文件,则必须创建Blob
。这个功能仍然是实验性的,但Chrome和Firefox支持(至少......和Safari我猜?):
var builder = new BlobBuilder();
builder.append(content);
var blob = builder.getBlob("application/zip");
请注意,目前您必须在Firefox中使用MozBlobBuilder
,而在Chrome中使用WebKitBlobBuilder
。
在一些教程中,我看到字符串实际上首先转换为Uint8Array
。也许这是基于较旧的引用,因为append
的{{1}}方法也应该接受普通字符串。从来没有尝试过。
如果您的内容是Base64编码的字符串,则必须使用BlobBuilder
对其进行转换(每个支持atob
和Blob
的浏览器都应该支持。
编辑:FormData
现已弃用。因此,获取BlobBuilder
所需要做的就是:
Blob
其余的很简单:
var blob = new Blob([content], "application/zip");
这里的问题是服务器端的文件名是不可预测的,并且取决于用户代理。我已经看到var form = new FormData();
form.append("file", blob);
的一些用法以及指定文件名的第三个参数,但我想将实际文件名发送到append
对象中的单独键/值对是个好主意。
答案 1 :(得分:1)
我终于明白了!!非常感谢MaxArt。
基本上,这是MaxArt对Uint8Array转换的说法。我从Eric Bidelman here获得了转换参考。
以下是我的表现:
var zip = new JSZip();
zip.file("hello1.txt", "Hello First World\n");
zip.file("hello2.txt", "Hello Second World\n");
var content = zip.generate(); //Generate dummy zip file (adjust to your need)
var oBlob = new (window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder)(); //Instantiate blob builder
var raw = atob(content); //decode the base64 string
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) { //convert to uInt8Array
uInt8Array[i] = raw.charCodeAt(i);
}
oBlob.append(uInt8Array.buffer); //append it to blobbuilder
oMyForm.append("GradeRequest[file]", oBlob.getBlob("application/zip")); //because you create a zip file, so get the zip type
//send it
var oReq = new XMLHttpRequest();
oReq.open("POST", "{{the_url}}");
oReq.send(oMyForm);