PUT 请求在 GET 和 POST 工作时失败 HTTP 预检(使用 Angular 6 和 Dotnet Core



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

我正在努力设置 API 以使用我的 Angular 服务。我的字体端和后端项目位于不同的本地主机端口上,但我已在 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 选项请求。谷歌搜索告诉我,这很可能是一个飞行前请求。然后它看到我的 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();
}

这感觉有点黑客,但现在它满足了我的需求。如果有人能阐明真正的问题可能是什么,我将不胜感激。

显然,这是使用 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响应和标头。

相关内容

  • 没有找到相关文章

最新更新