Angular2 中的 Http PUT 到 .NET Core Web API 提供来自预检请求的 http 401 错误

Posted

技术标签:

【中文标题】Angular2 中的 Http PUT 到 .NET Core Web API 提供来自预检请求的 http 401 错误【英文标题】:Http PUT in Angular2 to .NET Core Web API gives http 401 error from the preflight request 【发布时间】:2017-02-09 15:08:45 【问题描述】:

我有一个 Angular2 应用程序,它对 .NET Core Web API 控制器执行 http PUT。当我运行该应用程序时,它首先发出 OPTIONS 预检请求并抛出 401 Unauthorized 错误。

XMLHttpRequest cannot load http://localhost:55137/api/Foo/2. Response for preflight has invalid HTTP status code 401

我尝试过直接从 Postman 执行 PUT,并且效果很好。不知道这是否相关,但我的 Angular 应用程序的 GET 也可以正常工作。我已经在文档和网络搜索的帮助下汇总了以下代码,但我还没有完全理解为什么 OPTIONS 飞行前请求是未经授权的?我尝试了一些方法,例如在 web.config 中删除和重新添加 OPTIONSVerbHandler。我还读到预检请求要求您不要发送凭据,但我不确定在我的情况下该怎么做。

我正在使用 Angular 2.0.0-rc.5 和 .NET Core 1.0.0,并在 IIS 8.5 上托管(在 Visual Studio 2015 中开发时使用 IISExpress)。

foo.service.ts:

import  Injectable  from "@angular/core";
import  Headers, Http, RequestOptions  from "@angular/http";
import  CONFIG  from "./../app.config";

@Injectable()
export class FooService 
    private _apiUrl: string = CONFIG.generalAPI;
    private _headers: Headers = new Headers( "Content-Type": "application/json" );

    constructor(private http: Http)  

    updateObj(fooObj: any): Promise<any> 
        let body: any = JSON.stringify(fooObj);
        let options: RequestOptions = new RequestOptions(
            headers: this._headers,
            withCredentials: true
        );
        let result: Promise<any> = this.http.put(this._apiUrl + "/Foo/" + fooObj.ID, body, options)
            .toPromise()
            .then(response => response.json())
            .catch(this.handleError);
        return result;
    

    private handleError(error: any): Promise<any> 
        console.error("An error occurred", error);
        return Promise.reject(error.message || error);
    

fooController.cs:

// PUT api/Foo/5
[HttpPut("id")]
public IActionResult Put(int id, [FromBody]FooClass obj)

    try
    
        _fooService.UpdateFoo(obj);
        return Ok();
    
    catch (Exception ex)
    
        return BadRequest("An error occurred. Message: " + ex.Message);
    

webAPI 应用的 web.config:

<customHeaders>
    <add name="Access-Control-Allow-Credentials" value="true" />
    <add name="Access-Control-Allow-Origin" value="http://localhost:44612" />
    <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
    <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept, Authorization" />
</customHeaders>

【问题讨论】:

我只在 ASP .NET MVC 中使用 [EnableCors()] 属性完成了它,我不知道这是否适用于您的框架,但我知道尝试使用自定义标题伪造它不是预期的方法。 如果您使用的是.NET Core 1.0.0,您如何使用web.config 如果您在 IIS 或 IISExpress 下托管,您仍然使用 web.config。 你确定它加载正确吗?你可以在中间件中做同样的事情。 你在 webapi 控制器上有Authorize 属性吗?如果是,它可能会在来自 Angular 的请求中期待 Authorization 标头。但根据您的代码,您只传递 content-type 标头。 【参考方案1】:

您可以在您的 ASP.NET 核心 web api 中启用像这样的 CORS,而不是 web.config-

首先,在project.json中添加依赖-"Microsoft.AspNetCore.Cors": "1.0.0",

然后像这样在startup.cs 中启用 CORS-

app.UseCors(builder => 
    builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials();
);

如果你想限制到特定的来源,那么你可以这样做-

app.UseCors(builder => builder.WithOrigins("example.com"));

您可以找到更多关于 CORS 的信息here

【讨论】:

正如我在之前的评论中提到的,我曾尝试在中间件中启用 CORS,但遇到了一些其他问题,因此在 web.config 中启用它。回到这条路线并让它这次工作。谢谢大家的建议。 这里是我用来指定具体来源、标头和方法的代码:builder.WithOrigins("http://localhost:XXXX").WithMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").WithHeaders("Origin", "X-Requested-With", "Content-Type", "Accept", "Authorization").AllowCredentials();【参考方案2】:

我在没有正文的 HttpPut 上遇到了同样的问题。 如果您不发送正文(即使是 null 或类似的内容),API 将返回 Unauthorized。

const url = `$this.apiEndPoints.kycCasesEndPoint/$clientId/assign`;
const headers = new HttpHeaders().set('Authorization', 'Bearer ' +  this.authService.authToken);
return this.http.put<KycCaseAssign>(url, null,  headers )

【讨论】:

以上是关于Angular2 中的 Http PUT 到 .NET Core Web API 提供来自预检请求的 http 401 错误的主要内容,如果未能解决你的问题,请参考以下文章

http.put 在使用 Chrome 但不是 IE 的 Angular 2 / Web API 中抛出错误

Angular2 http响应正文出错

Angular2/Spring Boot 允许 PUT 上的跨域

为啥在我的 Angular 2 应用程序中发送 OPTIONS 请求而不是 PUT? [复制]

Angular 2 Http 删除与 Web API REST 一起使用的标头

Spring/JPA/Jackson 中的 Diff HTTP PUT 方法