使用POST的JQuery Form插件文件上载重定向到POST响应



请帮帮伙计们,这是一个主要的BLOCKER

我有一个使用NodeJS+jQuery表单插件+Typescript的项目,我正在尝试在其中进行文件上传。文件上传后,服务器发送对POST消息的响应,POST消息显示在屏幕上。在POST响应呈现在屏幕上之前,文件确实成功且完整地上传了。我希望POST响应调用"success"函数,而不是重定向页面以显示JSON响应。

这是代码:

$(new ID().setAsRoot().selectId()).append(
"<form id="fileUploadForm" accept-charset="utf-8" method="post" action="/upload" enctype="multipart/form-data">" +
"<input id = "filename" type="file" name="userfile" multiple="multiple" />" +
"<button type="submit" id = "submitButton"> Upload </button></form>");
var form = $("#fileUploadForm");
form.submit(function (e) {
//e.preventDefault();
this.ajaxSubmit({
type: form.attr('method'),
url: form.attr('action'),
data: form.serialize(),
success: function (data) {
var x = JSON.parse(data);
alert("Success : " + x);
},
error: function (data) {
var x = JSON.parse(data);
alert("Error : " + x);
}
});
});

success函数不会被调用(这意味着警报消息不会显示)。JSON数据在屏幕上呈现如下:

{
"path": "data\cb3409f1cc234ec3f64b60d80be13a3e.html",
"name": "feed.html"
}

控制台上有一个错误,上面写着:

Uncaught SyntaxError: Unexpected token : shortcut_manager.js:123
(anonymous function) shortcut_manager.js:123
(anonymous function) extensions::messaging:327
Event.dispatchToListener extensions::event_bindings:386
Event.dispatch_ extensions::event_bindings:371
Event.dispatch extensions::event_bindings:392
dispatchOnMessage

这是处理它的服务器端代码。服务器使用NodeJS强大的模块。

public upload(req:express.Request, res) {
var form = new formidable.IncomingForm();
var originalFileName:String;
var filePath:String;
form.uploadDir = this.directory;
form.keepExtensions = true;
form.type = 'multipart';
var fields = [];
form
.on("error", function (err) {
})
.on("field", function (field, value) {
})
.on("end", function () {
res.send({
path: filePath,
name: originalFileName
});
})
.on("file", function (name, file:formidable.File) {
originalFileName = file.name;
filePath = file.path;
});
form.parse(req);
return;
}

--更新--

如果我执行$.ajax而不是this.ajax。文件未上载。浏览器控制台显示错误:

XMLHttpRequest cannot load http://localhost/. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. 

基于您的评论:

"谢谢你的建议。$.ajax根本不加载。它显示了一个你可能知道的错误。虽然你的怀疑是正确的,因为当我使用"this.ajax"时,文件确实被上传了,但控制台显示了一条错误"Type has no method ajax">

  • 您不能像通常上传表单数据那样使用$.ajax()上传文件
  • 由于使用this.ajax时出现错误,表单将被提交。这就是您在浏览器中看到JSON响应的原因

问题是this.ajax来自哪里?您是否复制了使用未包含库的示例中的代码?

为了通过AJAX上传文件,你需要某种插件(自己做需要一些努力,尤其是如果你需要对旧浏览器的支持)。

更新

提交处理程序应如下所示:

form.submit(function (e) {
e.preventDefault();
$(this).ajaxSubmit().done(function (data) {
var x = JSON.parse(data);
alert("Success : " + x);
}).fail(function (data) {
var x = JSON.parse(data);
alert("Error : " + x);
});
});

说明:由于要调用jQuery插件,因此需要一个jQuery对象,因此需要$(this)ajaxSubmit()不需要任何参数(不过,如果需要,可以传入选项)。因为我没有传入参数,所以会附加回调,在本例中使用donefail(而不是successerror)。

替换this.ajax("http://..."到url:form.attr('method')

var form = $("#fileUploadForm");     
$.ajax({
type:form.attr('method'),
url:form.attr('action'),
data:form.serialize(),
success: function(data){
}});

您是否在问我为什么会出现错误:

XMLHttpRequest无法加载localhost/。请求的资源上不存在"Access Control Allow Origin"标头。因此,不允许访问源"localhost:8080"。

如果是这样,那么本地主机服务器(假设它也是Node)上需要的是来自localhost的响应上的一个标头集,以允许localhost:8080的Origin访问此资源,如下所示:

res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080');

或者,你实际上试图从同一台服务器请求,但忘记了8080是你的测试服务器:如果是这样,那么在你的测试中,你应该将你的URL列为

$.ajax("http://localhost:8080", { //....

或重复当前原点:

$.ajax( window.location.origin,{ // ....

避免这种情况的最后一种选择(如果你不能在响应上设置Origin策略)是使用jsonp服务,它不那么严格,但功能也不那么强大,但这不适合你的任务,所以我就不谈了。

无论哪种方式,一旦你通过了原产地政策,你就会遇到@zeroflagL提到的其他障碍。这里有一个可能适合您的方法:如何处理跨域iframe文件上传json响应?

我认为客户端代码存在几个不同的问题。

我看到你定义了$form,但我从来没有看到你在哪里定义form。然后拨打form.attr(...)。除非您在其他地方定义了form,否则这将立即引发错误。

更重要的是,标准$.ajax()无法在较旧的浏览器上上传文件(即使是最新的IE 9!)XHR2中添加了进行XHR文件上传的功能(请参阅CanIUse)。如果你想让你的网络应用程序与任何底层浏览器兼容,你需要以某种方式绕过这个限制。

好消息是,有各种各样的插件可以为您完成大部分工作。如果您使用的jQuery版本大于1.6,我建议您查看jQuery文件上传插件。它在可用时使用新的XHR文件上传功能,并在不支持新热点的浏览器中使用iFrame传输。虽然iFrame Transport简单而聪明,但您并不需要了解它,因为插件将其抽象化。这个插件也是完全免费的。

基本插件将为你做肮脏的工作,全功能版本甚至有一个内置的UI。还有很多关于如何实现服务器端方法的细节。基本语法非常简单:

$("#fileUploadForm").fileupload()

如果你正在寻找重量更轻的东西,iFrame传输插件可能就是你所需要的。(它也是免费的。)我今天刚刚在一个项目中实现了它。这是一个文档非常好的JS文件。它增强了$.ajax()功能的标准功能。关键是在AJAX选项列表中指定iframe: true。您的ajax调用可能看起来像这样:

$.ajax("http://localhost", {
type: $form.attr('method'),
url: $form.attr('action'),
data: $form.serialize(),
dataType: "JSON",
iframe: true,
files: $("#MyFileInputId"),
success: function (data) {
alert("Success : " + data);
},
error: function (data) {
alert("Error : " + data);
}
});

顺便说一句,如果你想让额外确保不会发生非AJAX POST,你可以在代码中添加另一行:

$form.submit(function (e) {
e.preventDefault();
// do stuff
return false;
}

preventDefault()将取消POST,即使下面的代码中出现错误。

var form = $("#fileUploadForm");     
$.ajax({
type:form.attr('method'),
url:form.attr('action'),
dataType: 'json', //  Expect a return value of json
data:form.serialize(),
success: function(data){
}});

最新更新