从插件的文档中引用:jquery.form
支持 XMLHttpRequest Level 2 的浏览器将能够无缝上传文件,甚至在上传过程中获得进度更新。对于较旧的浏览器,使用涉及 iframe 的后备技术,因为无法使用 XMLHttpRequest 对象的 1 级实现来上传文件。这是一种常见的后备技术,但它具有固有的局限性。iframe 元素用作表单提交操作的目标,这意味着将服务器响应写入 iframe。如果响应类型是 HTML 或 XML,这很好,但如果响应类型是脚本或 JSON,则效果不佳,这两种类型通常都包含在 HTML 标记中找到时需要使用实体引用来表示的字符。
为了解决使用 iframe 模式时脚本和 JSON 响应的挑战,Form Plugin 允许将这些响应嵌入到 textarea 元素中,建议您在与文件上传和旧版本结合使用时对这些响应类型这样做浏览器。但是请注意,如果表单中没有文件输入,则请求使用普通 XHR 提交表单(不是 iframe)。这给你的服务器代码增加了知道什么时候使用 textarea 什么时候不使用的负担。
这意味着如果您的表单包含文件输入字段并且您将此表单提交给返回 JSON 的控制器操作,则必须将此 JSON 包装在<textarea>
标签中。
所以你的回复不应该是这样的:
{ "redirectToUrl":"some url" }
它应该是这样的:
<textarea>{ "redirectToUrl":"some url" }</textarea>
为了实现这一点,您可以使用自定义操作结果,该结果将使用这些标签包装响应:
public class TextareaJsonResult : JsonResult
{
public TextareaJsonResult(object data)
{
this.Data = data;
}
public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.Response;
bool shouldWrap = !context.HttpContext.Request.IsAjaxRequest();
if (shouldWrap)
{
response.Write("<textarea>");
}
base.ExecuteResult(context);
if (shouldWrap)
{
response.ContentType = "text/html";
response.Write("</textarea>");
}
}
}
然后让您的控制器操作返回此自定义结果:
[HttpPost]
public ActionResult Upload(HttpPostedFileBase file)
{
// ... some processing
var redirectToUrl = Url.Action(
"Create",
"Album",
new { url = url, isLocalFile = isLocalFile }
);
return new TextareaJsonResult(new { redirectToUrl = redirectToUrl });
}
现在显然在您的 AJAX 成功回调中,您还需要通过测试typeof result
和在旧版浏览器(例如 Internet Explorer)的情况下手动解析响应来解释这种差异。您可以查看我链接到的页面的源代码。
但是话虽如此,我可以看到在您的成功回调中,您正在重定向到服务器返回的 JSON 响应中包含的控制器操作。我的问题来了:如果要重定向,首先使用 AJAX 有什么意义?为什么不使用标准表单发布到控制器操作并让控制器操作直接执行重定向?当您想留在同一页面上时,应该使用 AJAX。