我正在使用前端的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请求。谷歌搜索有点告诉我,这很可能是preflight request。然后,它发现我的API中不存在OPTIONS方法,并返回404。
我不明白为什么在这种情况下预检请求失败。为什么我的API可以用于GET和POST请求,而不能用于PUT?有人可以说明这里可能出了什么问题。
谢谢!
答案 0 :(得分:0)
我设法通过手动捕获预检请求并返回响应来解决此问题:
[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();
}
这感觉有点破烂,但是现在它可以满足我的需求。如果有人能阐明真正的问题是什么,我仍将不胜感激。
答案 1 :(得分:0)
当使用Windows身份验证(NTLM)和使用cors时,这显然是asp.net核心中的错误。当浏览器发送预检OPTIONS
请求时,它不需要进行身份验证,但是服务器将其视为需要身份验证来处理,从而导致401
错误。
我在这里找到并修改了一个解决方案:https://github.com/e5Workflow/CoreWebApp
那里的解决方案显然有些过时了,因为它在我的aspnetcore 2.1应用程序中不起作用,但是我从代码中挑选了相关的部分并使之起作用。
通过编辑launchsettings.json
"windowsAuthentication": true,
"anonymousAuthentication": true,
在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
响应和标头将被发回。