使用ASP.NET MVC和JQuery表单插件/文件上传检测IsAjaxRequest()

9
我正在使用JQuery Form插件在ASP.NET MVC应用程序上进行文件上传。我了解到,由于使用iframe进行文件上传(而不是不可能的XMLHttpRequest),因此服务器端检查IsAjaxRequest失败。
我看到了一些与这个问题相关的帖子,但没有找到任何好的解决方法来解决这个问题。与我的应用程序的其余部分一样,我希望能够支持启用JavaScript和禁用JavaScript的情况,这就是为什么我想检测请求是否为ajax的原因。
我意识到使用的iframe方法在技术上并不是ajax,但我正在尝试模仿ajax效果。
欢迎任何建议。
4个回答

11

从ASP.NET MVC 2开始(以及之后的版本),在Request上有一个扩展方法。

if (Request.IsAjaxRequest())
{
     // was an ajax request
}

使用像.load()这样的 jQuery 方法调用控制器方法将导致 Request.IsAjaxRequest() 返回 true。


11

你需要为“IsAjaxRequest”方法设置“X-Requested-With”标题,以使其返回真。以下是在jquery中实现此操作的方法。

$(document).ready(function() {
     jQuery.ajaxSetup({
          beforeSend: function (xhr) {
                xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
                return xhr;
          }
     });
});

JQuery表单插件不使用XMLHttpRequest进行文件上传,而是使用一个iframe。 - goombaloon
1
在Angular中对我很有用:$httpProvider.defaults.headers.common = { 'X-Requested-With' : 'XMLHttpRequest' }; - parliament

9

我刚意识到我完全没有回答问题,所以我在这里添加内容,并保留我的旧答案:

问题在于,在通过iFrame上传文件时,"X-Requested-With"头未设置,并且您无法在JavaScript中为普通表单POST设置特定的请求头。您将不得不采用其他技巧,比如使用POST发送包含值的隐藏字段,然后更改或覆盖“IsAjaxRequest”扩展方法,也检查此条件。 如何覆盖现有的扩展方法?

可能最好的选择是在默认的MVC扩展方法代码基础上包含自己的扩展方法,并更改以检测您的iFrame上传POST,然后在需要使用它的任何地方都使用您的扩展方法。


实际上,jQuery默认将'X-Requested-With'头设置为'XMLHttpRequest'。 只要您小心地使用所有AJAX调用,它就非常有用。

根据您的需求,很容易在操作过滤器中设置检测以在需要时使用它,甚至可以将其构建到控制器类中,如下所示:

[jQueryPartial]
public abstract class MyController : Controller
{
   public bool IsAjaxRequest { get; set; }
}

动作过滤器特性:

public class jQueryPartial : ActionFilterAttribute  
{  
    public override void OnActionExecuting(ActionExecutingContext filterContext)  
    { 
        // Verify if a XMLHttpRequest is fired.  
        // This can be done by checking the X-Requested-With  
        // HTTP header.  
        MyController myController = filterContext.Controller as MyController;
        if (myController != null)
        {
            if (filterContext.HttpContext.Request.Headers["X-Requested-With"] != null
                && filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
            {
                myController.IsAjaxRequest = true;
            }
            else
            {
                myController.IsAjaxRequest = false;
            }
        }
    }
}

使用该实现:

public class SomeController : MyController
{
    public ActionResult Index()
    {
          if (IsAjaxRequest)
               DoThis();
          else
               DoThat();

          return View();
    }
}

在你的代码中,IsAjaxRequest 总是为 true,这违背了代码的目的...而且这与扩展方法中存在的相同功能一样...所以这真的对你没有帮助。 - zowens
1
感谢提供的信息。按照您的建议,我最终通过JQuery动态添加了一个隐藏表单值(“isFileUploadAjaxPost”)。在控制器中,我检查该表单变量。如果存在,我使用TempData存储此值,然后调用RedirectToAction显示新上传文件的“编辑”视图。在接收操作方法中,我检查Request.IsAjaxRequest()(一直以来都是这样做的)以及我的TempData值,以确定请求是否为“ajax”。效果很好。谢谢! - goombaloon
@zowens:我现在已经修复了代码,但是是的,在制作它并查看IsAjaxRequest扩展方法之后,我意识到它们完全相同。我从一个ActionFilter中调整了代码,该过滤器根据请求类型动态设置主页面,这当然比上面的代码少了一些冗余。 - Jay
简洁:var requestWith = filterContext.HttpContext.Request.Headers["X-Requested-With"]; myController.IsAjaxRequest = requestWith == "XMLHttpRequest;" - Devin Burke

2

我刚偶然发现了这个问题,后来找到了更好的解决方案,所以在此为每个从谷歌搜索到这里的人提供以下解决方法:

jQuery表单插件有两个选项可能会对此有帮助。

  1. 如果您正在使用post请求,则似乎始终使用iframe,因此如果您不需要文件上传,请在Form选项中设置"iframe = false"可以解决问题。

  2. 如果您需要iframe进行文件上传,您可以使用data属性的选项来欺骗

    IsAjaxRequest()设置 : data: { "X-Requested-With": "XMLHttpRequest" }

具有两个选项的完整脚本看起来像这样:

$('#someform').ajaxForm(
{
        dataType: 'json',
        success: onSuccess,
        error: onError,
                iframe: false
        data: { "X-Requested-With": "XMLHttpRequest" } 
    }
);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接