Http PUT в Angular2 для .NET Core Web API выдает ошибку http 401 из предварительного запроса

У меня есть приложение Angular2, которое выполняет http PUT для контроллера веб-API .NET Core. Когда я запускаю приложение, оно сначала делает предварительный запрос OPTIONS и выдает ошибку 401 Unauthorized.

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

Я пытался выполнить PUT непосредственно из Postman, и он отлично работает. Не знаю, актуально ли это, но мои GET из приложения Angular тоже работают нормально. Я собрал следующий код с помощью документации и поиска в Интернете, но я недостаточно хорошо понимаю, чтобы понять, почему предварительный запрос OPTIONS неавторизован? Я пробовал несколько вещей, таких как удаление и повторное добавление OPTIONSVerbHandler в файле web.config. Я также читал, что предварительный запрос требует, чтобы вы НЕ отправляли учетные данные, но я не уверен, как это сделать в моем случае.

Я использую Angular 2.0.0-rc.5 и .NET Core 1.0.0 и размещаюсь на IIS 8.5 (IISExpress при разработке в Visual Studio 2015).

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);
    }
}

web.config для приложения webAPI:

<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>

person Jerms    schedule 01.10.2016    source источник
comment
Я сделал это только в ASP .NET MVC, используя атрибут [EnableCors()], и я не знаю, будет ли это работать для вашей среды, но я знаю, что попытка подделать его с помощью пользовательских заголовков не будет намеченный подход.   -  person LinuxDisciple    schedule 01.10.2016
comment
Как вы используете web.config, если вы используете .NET Core 1.0.0?   -  person Brad    schedule 01.10.2016
comment
Вы по-прежнему используете web.config, если размещаете под IIS или IISExpress.   -  person Jerms    schedule 01.10.2016
comment
Вы уверены, что он загружается правильно? Вы можете сделать то же самое в промежуточном программном обеспечении.   -  person Brad    schedule 01.10.2016
comment
У вас есть атрибут Authorize на контроллере webapi. Если да, возможно, ожидается заголовок Authorization в запросе, поступающем от Angular. Но согласно вашему коду вы передаете только заголовок content-type.   -  person Venky    schedule 01.10.2016
comment
@Brad Пробовал промежуточное ПО, когда я впервые начал проект, и столкнулся с некоторыми проблемами, поэтому я перешел к настройке CORS в web.config. Попробовал вернуться к промежуточному программному обеспечению и на этот раз все заработало.. спасибо.   -  person Jerms    schedule 03.10.2016


Ответы (2)


Вместо web.config вы можете включить CORS, подобный этому, в своем основном веб-API ASP.NET.

Во-первых, добавьте зависимость в project.json - "Microsoft.AspNetCore.Cors": "1.0.0",

затем включите CORS в startup.cs вот так:

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

В случае, если вы хотите ограничиться конкретным источником, вы можете сделать так:

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

Дополнительную информацию о CORS можно найти здесь

person Sanket    schedule 01.10.2016
comment
Как я упоминал в предыдущем комментарии, я пытался включить CORS в промежуточном программном обеспечении, но столкнулся с некоторыми другими проблемами, поэтому прибегнул к включению его в web.config. Вернулся к этому маршруту и ​​заставил его работать на этот раз. Спасибо за предложения всем. - person Jerms; 03.10.2016
comment
Вот код, который я использовал для указания конкретного источника, заголовков и методов: builder.WithOrigins("http://localhost:XXXX").WithMethods("GET", "POST", "PUT", "DELETE", "OPTIONS").WithHeaders("Origin", "X-Requested-With", "Content-Type", "Accept", "Authorization").AllowCredentials(); - person Jerms; 03.10.2016

У меня была такая же проблема с HttpPut без тела. Если вы не отправите тело (даже нулевое или что-то в этом роде), 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 })

person Felix Prados    schedule 25.10.2017