简体   繁体   English

GET和POST工作时,PUT请求失败,HTTP预检失败(使用Angular 6和Dotnet Core 2.1 Web API)

[英]PUT Request fails HTTP preflight while GET and POST work (Using Angular 6 and Dotnet Core 2.1 Web API)

I'm developing a web application using Angular 6 on the front-end and .NET Core Web API on the back-end. 我正在使用前端的Angular 6和后端的.NET Core Web API开发Web应用程序。

I'm working on setting up the API to work with my Angular services. 我正在设置API以与Angular服务一起使用。 My font-end and back-end projects are on different localhost ports, but I've enabled CORS for development purposes in my API as such. 我的字体末端项目和后端项目位于不同的localhost端口上,但是我已经出于开发目的在API中启用了CORS。

services.AddCors(o => o.AddDefaultPolicy(builder =>
{
    builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader();
}));

Using this setup, I can successfully execute a GET request. 使用此设置,我可以成功执行GET请求。 For example, my Angular service: 例如,我的Angular服务:

getAllFiles():Observable<MediaFile[]> {
  return this.http.get<MediaFile[]>(`${this.request_url}/files`)
}

Can call my Web API Controller: 可以调用我的Web API控制器:

[HttpGet]
public IEnumerable<MediaFile> GetFiles(string code = null)
{
    if (code != null)
    {
      return context.Files.Where(file => file.Meeting.Code == code);
    }
    return context.Files;
}

And successfully gives me the media files I've requested. 并成功提供了我所请求的媒体文件。

I won't include it here for brevity purposes, but I've done the same thing for POST and it works as expected. 为了简洁起见,我不会在此处包括它,但是我对POST做过同样的事情,并且它按预期工作。

I'm trying to add a handler for PUT requests. 我正在尝试为PUT请求添加处理程序。 Here is the relevant code: 以下是相关代码:

putFile(file:MediaFile):Observable<MediaFile> {
  return this.http.put<MediaFile>(
    `${this.request_url}/files/${file.id}`, file
  )
}

And on the server-side: 在服务器端:

[HttpPut("{id}")]
public async Task<IActionResult> PutFile([FromRoute] int id, [FromBody] MediaFile file)
{
   if (!ModelState.IsValid)
   {
      return BadRequest(ModelState);
   }

   if (id != file.Id)
   {
      return BadRequest();
   }

   context.Entry(file).State = EntityState.Modified;

   try
   {
      await context.SaveChangesAsync();
   }
   catch (DbUpdateConcurrencyException)
   {
     if (!FileExists(id))
     {
       return NotFound();
     }
     else
     {
        throw;
      }
    }
    return NoContent();
}

But when I try executing this code, the browser sends an HTTP OPTIONS request. 但是,当我尝试执行此代码时,浏览器会发送HTTP OPTIONS请求。 A bit of Googling has told me that this is most likely a preflight request . 谷歌搜索有点告诉我这很可能是一个飞行前的要求 It then sees that no OPTIONS method exists in my API, and returns a 404. 然后,它发现我的API中不存在OPTIONS方法,并返回404。

I don't understand why the preflight request is failing under these circumstances. 我不明白为什么在这种情况下预检请求失败。 Why does my API work with GET and POST requests, but not with PUT? 为什么我的API可以用于GET和POST请求,而不能用于PUT? Could somebody please shed some light on what could be going wrong here. 有人可以告诉我们这里可能出什么问题了。

Thanks! 谢谢!

I managed to fix this issue by manually catching the preflight request and returning a response: 我设法通过手动捕获预检请求并返回响应来解决此问题:

[HttpOptions("{id}")]
public IActionResult HandleOptions([FromRoute] int id)
{
      Request.HttpContext.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
      Request.HttpContext.Response.Headers.Add("Access-Control-Allow-Headers", "origin, content-type, accept, x-requested-with");
      Request.HttpContext.Response.Headers.Add("Access-Control-Max-Age", "3600");
      return Ok();
 }

This feels like a bit of hack, but for now it serves my needs. 感觉有点像hack,但是现在它可以满足我的需求。 I would still appreciate if someone could shed light on what the real problem could be. 如果有人能阐明真正的问题,我仍将不胜感激。

Apparently this is a bug in asp.net core when using Windows Authentication (NTLM) and using cors. 显然,这是使用Windows身份验证(NTLM)和cors时asp.net核心中的错误。 When the browser sends the preflight OPTIONS request, it should not require authentication, but the server handles it as if authentication is required, resulting in the 401 error. 当浏览器发送预检OPTIONS请求时,它不需要进行身份验证,但是服务器将其视为需要身份验证来处理,从而导致401错误。

I found and modified a solution from here: https://github.com/e5Workflow/CoreWebApp 我从这里找到并修改了一个解决方案: https : //github.com/e5Workflow/CoreWebApp

The solution there was apparently a bit outdated as it did not work in my aspnetcore 2.1 app, but I picked the relevant bits out of the code and made it work. 那里的解决方案显然有些过时了,因为它在我的aspnetcore 2.1应用程序中不起作用,但是我从代码中挑选了相关的部分并使之起作用。

  1. Enable anonymous authentication by editing launchsettings.json 通过编辑launchsettings.json启用匿名身份验证

     "windowsAuthentication": true, "anonymousAuthentication": true, 
  2. Add the following as your very first middleware in startup.cs : 将以下内容作为您的第一个中间件添加到startup.cs

     app.Use(async (context, next) => { if(context.Request.Method != "OPTIONS" && !context.User.Identity.IsAuthenticated) { context.Response.StatusCode = 401; await context.Response.WriteAsync("Not Authenticated"); } else { await next.Invoke(); } }); 

The idea is that every request except an OPTIONS request will still require authentication, but OPTIONS requests will not, so the proper 200 response and headers will be sent back. 这个想法是,除了OPTIONS请求之外的每个请求都仍将需要身份验证,而OPTIONS请求则不需要,因此将发送回正确的200响应和标头。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM