Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angularjs ASP.NET WebAPI2 CORS:飞行前GetOwinContext中的空请求_Angularjs_Cors_Owin_Asp.net Web Api2 - Fatal编程技术网

Angularjs ASP.NET WebAPI2 CORS:飞行前GetOwinContext中的空请求

Angularjs ASP.NET WebAPI2 CORS:飞行前GetOwinContext中的空请求,angularjs,cors,owin,asp.net-web-api2,Angularjs,Cors,Owin,Asp.net Web Api2,我正在创建一个带有WebAPI2后端的AngularJS Typescript SPA,需要API的身份验证和授权。API托管在不同的服务器上,所以我使用CORS,主要遵循在上的指导,因为我是这个领域的新手 一切正常,我可以注册和登录,然后通过在客户端服务中传递接收到的访问令牌,并使用以下相关代码,从默认VS WebAPI 2模板向受限访问控制器操作(此处为虚拟值控制器)发出请求: private buildHeaders() { if (this.settings.token) {

我正在创建一个带有WebAPI2后端的AngularJS Typescript SPA,需要API的身份验证和授权。API托管在不同的服务器上,所以我使用CORS,主要遵循在上的指导,因为我是这个领域的新手

一切正常,我可以注册和登录,然后通过在客户端服务中传递接收到的访问令牌,并使用以下相关代码,从默认VS WebAPI 2模板向受限访问控制器操作(此处为虚拟值控制器)发出请求:

private buildHeaders() {
    if (this.settings.token) {
        return { "Authorization": "Bearer " + this.settings.token };
    }
    return undefined;
}

public getValues(): ng.IPromise<string[]> {
    var deferred = this.$q.defer();
    this.$http({
        url: this.config.rootUrl + "api/values",
        method: "GET",
        headers: this.buildHeaders(),
    }).success((data: string[]) => {
        deferred.resolve(data);
    }).error((data: any, status: any) => {
        deferred.reject(status.toString() + " " +
            data.Message + ": " +
            data.ExceptionMessage);
    });
    return deferred.promise;
}
然后,我将此代码添加到我的登录控制器:

private loadUserRoles() {
    this.accountService.getUserRoles()
        .then((data: string[]) => {
            // store roles in an app-settings service
            this.settings.roles = data;
        }, (reason) => {
            this.settings.roles = [];
        });
}

public login() {
    if ((!this.$scope.name) || (!this.$scope.password)) return;

    this.accountService.loginUser(this.$scope.name,
            this.$scope.password)
        .then((data: ILoginResponseModel) => {
            this.settings.token = data.access_token;
            // LOAD ROLES HERE
            this.loadUserRoles();
        }, (reason) => {
            this.settings.token = null;
            this.settings.roles = [];
        });
}
其中,账户控制员的方法是:

public getUserRoles() : ng.IPromise<string[]> {
    var deferred = this.$q.defer();
    this.$http({
        url: this.config.rootUrl + "api/account/userroles",
        method: "GET",
        headers: this.buildHeaders()
    }).success((data: string[]) => {
        deferred.resolve(data);
    }).error((data: any, status: any) => {
        deferred.reject(status.toString() + ": " +
            data.error + ": " +
            data.error_description);
    });
    return deferred.promise;            
}
无论如何,这会触发一个OPTIONS飞行前请求,从而导致500错误。如果我检查响应,我可以看到GetOwinContext方法得到一个空请求。以下是错误堆栈跟踪的开始:

{消息:发生错误,异常消息:值不能为空。\r\n参数名称:请求,异常类型:System.ArgumentNullException,stackTrace:at System.Net.Http.OwinHttpRequestMessageExtensions.GetowInTextHttpRequestMessage请求\r\n at Accounts.Web.Controllers.AccountController.get\u UserManager…}

然而,我用于获取角色的代码与我用于从WebAPI测试控制器获取虚拟值的代码没有什么不同。我不能确切地理解为什么这里需要预飞行,但无论如何,我在OWIN代码中遇到了这个令人讨厌的异常

我的请求头是端口49592处的API:

选项/api/account/userroles HTTP/1.1 主机:本地主机:49592 连接:保持活力 访问控制请求方法:GET 来源:http://localhost:64036 用户代理:Mozilla/5.0 Windows NT 6.3;WOW64 AppleWebKit/537.36 KHTML,如Gecko Chrome/35.0.1916.153 Safari/537.36 访问控制请求头:接受、授权 接受:*/* 推荐人:http://localhost:64036/ 接受编码:gzip、deflate、sdch 接受语言:en-US,en;q=0.8,it;q=-5.4


有人能解释一下吗?

我想我找到了某种有效的解决方案,即使它看起来有点脏,但至少它是有效的。我把它贴在这里,这样其他人最终可以利用它,但我愿意接受建议。很抱歉,格式错误,但我尝试了几次,编辑器不允许我正确标记代码

从本质上说,解决方案是由对这篇文章的回答提出的:,但我更改了不适用于我的WebAPI 2和.NET 4.5.1的代码。这是:

在Global.asax的方法Application\u Start中,添加BeginRequest+=Application\u BeginRequest

添加覆盖,它通过允许在我的测试环境中一切正常来响应选项请求:

受保护的无效应用程序\u开始请求对象发送方,事件参数e { if Request.Headers.AllKeys.ContainsOrigin&& Request.HttpMethod==选项 { Response.StatusCode=200; Response.Headers.AddAccess-Control-Allow-Origin,*; Response.Headers.AddAccess-Control-Allow-Methods、GET、PUT、POST、DELETE

  string sRequestedHeaders = String.Join(", ",
      Request.Headers.GetValues("Access-Control-Request-Headers") ?? new string[0]);
  if (!String.IsNullOrEmpty(sRequestedHeaders))
      Response.Headers.Add("Access-Control-Allow-Headers", sRequestedHeaders);

  Response.End();
} }

修饰accounts controller方法的属性只是RouteAttribute:

[RouteUserRoles] 公共字符串[]GetUserRoles { string id=User.Identity.GetUserId; Debug.asserted!=null; 字符串[]aRoles=UserManager.GetRolesid.ToArray; 返回aRoles; }

通过这种方式,OPTIONS请求得到正确的响应,随后的GET成功

加成

我还必须补充一点,EnableCors属性是不够的,因为我们不仅必须处理OPTIONS动词,还必须确保任何CORS请求都获得accesscontrolalloworigin头。否则,您可能会看到明显正确的响应代码200等,但看到$http调用失败。在我的例子中,我将这一行添加到global.asax:

GlobalConfiguration.Configuration.MessageHandlers.Add(new CorsAllowOriginHandler());
My CorsAllowOriginHandler是一个DelegatingHandler,它只需确保在请求包含原始标头的每个响应中都存在此值为*的标头:


你确定User.Identity.GetUserId有一个值吗?我不能在那里设置断点,异常在我的代码之外和之前由管道中前面的OWIN抛出。我也这么认为,但后来我发现断点从未命中,堆栈跟踪指向参数请求为null的OWIN方法。我必须补充一点,我尝试了以下方法:a如中所建议,我添加了应用程序_BeginRequest,如文章中所指定,但这会触发另一个异常:System.Web.HttpException:发送HTTP头后,服务器无法设置状态;b正如文档中所建议的,我用[AcceptVerbsnew[]{GET}]修饰了控制器操作,但没有选项,以避免MVC对选项请求造成混乱,但这似乎没有任何效果。还有其他想法吗?您是否确保在web.config中设置了允许的动词包含选项?谢谢,我的web.config基本上没有受到webapi标准te的影响 安普拉特。我能找到的选项的唯一引用位于system.webServer/handlers:。我试着把它移走,但什么也没变。
GlobalConfiguration.Configuration.MessageHandlers.Add(new CorsAllowOriginHandler());
public sealed class CorsAllowOriginHandler : DelegatingHandler
{
    protected async override Task<HttpResponseMessage> SendAsync
        (HttpRequestMessage request, CancellationToken cancellationToken)
    {
        HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

        // all CORS-related headers must contain the Access-Control-Allow-Origin header,
        // or the request will fail. The value may echo the Origin request header, 
        // or just be `*`.
        if ((request.Headers.Any(h => h.Key == "Origin")) &&
            (response.Headers.All(h => h.Key != "Access-Control-Allow-Origin")))
        {
            response.Headers.Add("Access-Control-Allow-Origin", "*");
        }
        return response;
    }
}