繁体   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)

我正在使用前端的Angular 6和后端的.NET Core Web API开发Web应用程序。

我正在设置API以与Angular服务一起使用。 我的字体末端项目和后端项目位于不同的localhost端口上,但是我已经出于开发目的在API中启用了CORS。

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

使用此设置,我可以成功执行GET请求。 例如,我的Angular服务:

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

可以调用我的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;
}

并成功提供了我所请求的媒体文件。

为了简洁起见,我不会在此处包括它,但是我对POST做过同样的事情,并且它按预期工作。

我正在尝试为PUT请求添加处理程序。 以下是相关代码:

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

在服务器端:

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

但是,当我尝试执行此代码时,浏览器会发送HTTP OPTIONS请求。 谷歌搜索有点告诉我这很可能是一个飞行前的要求 然后,它发现我的API中不存在OPTIONS方法,并返回404。

我不明白为什么在这种情况下预检请求失败。 为什么我的API可以用于GET和POST请求,而不能用于PUT? 有人可以告诉我们这里可能出什么问题了。

谢谢!

我设法通过手动捕获预检请求并返回响应来解决此问题:

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

感觉有点像hack,但是现在它可以满足我的需求。 如果有人能阐明真正的问题,我仍将不胜感激。

显然,这是使用Windows身份验证(NTLM)和cors时asp.net核心中的错误。 当浏览器发送预检OPTIONS请求时,它不需要进行身份验证,但是服务器将其视为需要身份验证来处理,从而导致401错误。

我从这里找到并修改了一个解决方案: https : //github.com/e5Workflow/CoreWebApp

那里的解决方案显然有些过时了,因为它在我的aspnetcore 2.1应用程序中不起作用,但是我从代码中挑选了相关的部分并使之起作用。

  1. 通过编辑launchsettings.json启用匿名身份验证

     "windowsAuthentication": true, "anonymousAuthentication": true, 
  2. 将以下内容作为您的第一个中间件添加到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(); } }); 

这个想法是,除了OPTIONS请求之外的每个请求都仍将需要身份验证,而OPTIONS请求则不需要,因此将发送回正确的200响应和标头。

暂无
暂无

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

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