首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >处理对ASP.NET MVC操作的CORS印前检查请求

处理对ASP.NET MVC操作的CORS印前检查请求
EN

Stack Overflow用户
提问于 2012-11-29 19:07:07
回答 6查看 48.1K关注 0票数 53

我正在尝试执行对ASP.NET MVC控制器操作的跨域POST请求。此控制器操作接受并使用各种参数。问题是,当印前检查请求发生时,控制器操作实际上会尝试执行&因为OPTIONS请求没有传递任何数据,所以控制器操作抛出一个500HTTP错误。如果我删除使用该参数的代码或参数本身,则整个请求链将成功完成。

这是如何实现的一个示例:

控制器操作

代码语言:javascript
复制
public ActionResult GetData(string data)
{
    return new JsonResult
    {
        Data = data.ToUpper(),
        JsonRequestBehavior = JsonRequestBehavior.AllowGet
    };
}

客户端代码

代码语言:javascript
复制
<script type="text/javascript">
        $(function () {
            $("#button-request").click(function () {
                var ajaxConfig = {
                    dataType: "json",
                    url: "http://localhost:8100/host/getdata",
                    contentType: 'application/json',
                    data: JSON.stringify({ data: "A string of data" }),
                    type: "POST",
                    success: function (result) {
                        alert(result);
                    },
                    error: function (jqXHR, textStatus, errorThrown) {
                        alert('Error: Status: ' + textStatus + ', Message: ' + errorThrown);
                    }
                };

                $.ajax(ajaxConfig);
            });
        });
    </script>

现在,无论何时发生印前检查请求,它都会返回一个500HTTP代码,因为"data“参数是空的,因为OPTIONS请求没有传递任何值。

服务器应用程序已经设置在我的本地IIS中的端口8100上&运行客户端代码的页面设置在端口8200上,以模拟跨域调用。

我还为主机(在8100上)配置了以下标头:

代码语言:javascript
复制
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Origin: http://localhost:8200

我发现的一种解决方法是检查执行操作的HTTP方法&如果是一个只返回空白内容的OPTIONS请求,则执行操作代码。如下所示:

代码语言:javascript
复制
public ActionResult GetData(string data)
{
    if (Request.HttpMethod == "OPTIONS") {
        return new ContentResult();
    } else {
        return new JsonResult
        {
            Data = data.ToUpper(),
            JsonRequestBehavior = JsonRequestBehavior.AllowGet
        };
    }
}

但这种方法对我来说非常笨拙。我考虑过将这种逻辑添加到Attribute中,但即使这样也意味着使用CORS来修饰将被调用的每个操作。

有没有更优雅的解决方案来让这个功能正常工作?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2012-11-30 21:24:51

所以我找到了一个可行的解决方案。对于每个请求,我检查它是否是CORS请求&请求是否带有OPTIONS动词,表明它是印前检查请求。如果是,我只发回一个空响应(当然只包含在IIS中配置的头),从而否定控制器操作的执行。

然后,如果客户端根据从印前检查返回的头部确认允许执行请求,则执行实际的POST &执行控制器操作。下面是我的代码示例:

代码语言:javascript
复制
protected void Application_BeginRequest()
{
    if (Request.Headers.AllKeys.Contains("Origin", StringComparer.OrdinalIgnoreCase) &&
        Request.HttpMethod == "OPTIONS") {
        Response.Flush();
    }
}

正如前面提到的,这对我很有效,但如果有人知道更好的方法,或者知道我当前实现中的任何缺陷,我将不胜感激。

票数 65
EN

Stack Overflow用户

发布于 2015-08-01 03:46:02

在卡尔回答的基础上,我将他的代码插入到我自己的管道中:

代码语言:javascript
复制
app.Use((context, next) =>
{
     if (context.Request.Headers.Any(k => k.Key.Contains("Origin")) && context.Request.Method == "OPTIONS")
     {
         context.Response.StatusCode = 200;
         return context.Response.WriteAsync("handled");
     }

     return next.Invoke();
});

只需将此代码添加到Startup.cs中IAppBuilder的开头(或在注册WebAPI之前的任何位置

票数 12
EN

Stack Overflow用户

发布于 2017-05-26 04:14:00

被接受的答案就像一个魔咒,但我发现请求实际上是向下传递给控制器的。我收到了一个200状态码,但响应正文包含了大量的HTML语言,但控制器却出现了异常。因此,我发现使用Response.End()比使用Response.Flush()更好,因为它确实会停止请求的执行。此替代解决方案将如下所示:

编辑:修复了原始答案中的一个拼写错误。

代码语言:javascript
复制
protected void Application_BeginRequest()
{
    if (Request.Headers.AllKeys.Contains("Origin", StringComparer.OrdinalIgnoreCase) &&
        Request.HttpMethod == "OPTIONS") {
        Response.End();
    }
}
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13624386

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档