在Stackoverflow上没有找到解决方法后,我解决了这个问题,现在分享我的问题以及答案。
在我的.NET Core Web Api应用程序中使用AddCors启用跨域策略后,从浏览器仍然无法工作。这是因为浏览器,包括Chrome和Firefox,将首先发送一个OPTIONS请求,而我的应用程序只会响应204 No Content。
在Stackoverflow上没有找到解决方法后,我解决了这个问题,现在分享我的问题以及答案。
在我的.NET Core Web Api应用程序中使用AddCors启用跨域策略后,从浏览器仍然无法工作。这是因为浏览器,包括Chrome和Firefox,将首先发送一个OPTIONS请求,而我的应用程序只会响应204 No Content。
向您的项目中添加一个中间件类以处理OPTIONS动词。
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Hosting;
namespace Web.Middlewares
{
public class OptionsMiddleware
{
private readonly RequestDelegate _next;
public OptionsMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext context)
{
return BeginInvoke(context);
}
private Task BeginInvoke(HttpContext context)
{
if (context.Request.Method == "OPTIONS")
{
context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { (string)context.Request.Headers["Origin"] });
context.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "Origin, X-Requested-With, Content-Type, Accept" });
context.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "GET, POST, PUT, DELETE, OPTIONS" });
context.Response.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });
context.Response.StatusCode = 200;
return context.Response.WriteAsync("OK");
}
return _next.Invoke(context);
}
}
public static class OptionsMiddlewareExtensions
{
public static IApplicationBuilder UseOptions(this IApplicationBuilder builder)
{
return builder.UseMiddleware<OptionsMiddleware>();
}
}
}
然后在Startup.cs文件中的Configure方法的第一行添加app.UseOptions();
。
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseOptions();
}
context.Response.WriteAsync("OK");
后请求应该结束,因此更改 Invoke
实现为:if (context.Request.Method != "OPTIONS")
{
await this._next.Invoke(context);
}
- Amen Ayachcontext.Response.WriteAsync("OK");
语句,因此在OPTIONS方法时不会到达_next.invoke(context)
。 - Jesse de gans我知道这个问题已经有了答案,只是想提供最新的信息以帮助其他人。
现在它已经集成到 ASP.NET Core 框架中。
只需按照 https://learn.microsoft.com/en-us/aspnet/core/security/cors 的步骤进行操作。
并替换
app.UseCors(builder =>
builder.WithOrigins("http://example.com"));
随着
app.UseCors(builder =>
builder.WithOrigins("http://example.com")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials());
WithHeaders
/WithMethods
方法。 - Gerrit-K204 No Content
是一个问题吗?似乎你从一个 OPTIONS
请求中应该期望的唯一信息只有在标头中。是这样吗?Mozilla 似乎也这么认为。 - Dan NarsavageStartup.cs
中的 Configure()
方法中。 - Luke这对我有效:
确保这个:
app.UseCors(builder => {
builder.AllowAnyOrigin();
builder.AllowAnyMethod();
builder.AllowAnyHeader();
});
发生在这些事件之前:
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseCookiePolicy();
记住,我们正在处理一个“管道”。cors的内容必须首先处理。
-gimzani
无需额外的中间件。如上所述,唯一需要的是在CORS配置中允许OPTIONS方法。 您可以像这里建议的那样使用AllowAnyMethod: https://dev59.com/H1gQ5IYBdhLWcg3wynGn#55764660
但更安全的做法是仅允许特定的内容,例如:
app.UseCors(builder => builder
.WithOrigins("https://localhost", "https://production.company.com") /* list of environments that will access this api */
.WithMethods("GET", "OPTIONS") /* assuming your endpoint only supports GET */
.WithHeaders("Origin", "Authorization") /* headers apart of safe-list ones that you use */
);
一些标头始终允许:
https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_request_headerAspNetCoreModuleV2 OPTIONS 问题
.Net Core 模块无法处理 OPTIONS 请求,这会导致预检请求(CORS)的问题,因此解决方案是将 OPTIONS 动词从处理中排除。这可以通过用想要的动词替换 "*"(所有动词)来实现,但需要保留 OPTIONS 动词。不用担心,OPTIONS 动词将由默认加载的 OPTIONSHandler 处理:
IIS
解决方案:修改 web.config
文件。
<add name="aspNetCore" path="*" verb="* modules="AspNetCoreModuleV2" resourceType="Unspecified" />
把它做成这样:
<add name="aspNetCore" path="*" verb="GET,POST,PUT,DELETE" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
IIS Express: 用于 Visual Studio 调试器
我尝试修改 .vs\ProjectName\config\applicationhost.config
文件,但是没有任何希望。因此,在这种特定情况下,您可以使用所选答案。
app.UseOptions();
app.UseCors(policy => policy.WithOrigins("https://localhost:44414")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials());
但是我仍然收到了Response to preflight request doesn't pass access control check
的错误。有什么建议吗? - undefinedbuilder.Services.AddControllers();
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder
.WithOrigins(
"https://myserver",
"http://localhost:8080")
.AllowCredentials()
.WithHeaders(HeaderNames.ContentType, "x-custom-header")
.AllowAnyMethod()
.WithExposedHeaders(HeaderNames.ContentType, "x-custom-header")
;
});
});
// Compressed responses over secure connections can be controlled with the EnableForHttps option, which is disabled by default because of the security risk.
builder.Services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
});
// SQL
string connectionString = builder.Configuration.GetConnectionString("WebApiDatabase");
builder.Services.AddDbContext<otscorecard_2022_webapi.Models.WebApiDbContext>(options =>
options.UseSqlServer(connectionString)
);
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme)
.AddNegotiate();
builder.Services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy.
options.FallbackPolicy = options.DefaultPolicy;
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseCors(); // IIS: enable both Windows (GET/PUT/POST/DELETE/ETC) and Anonymous Authentication (used for OPTIONS/PreFlight)
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.UseResponseCompression();
app.Run();
我希望允许单个方法执行此操作,而不是使用中间件来允许任何方法执行此操作。这就是我最终所做的:
[HttpOptions("/find")]
public IActionResult FindOptions()
{
Response.Headers.Add("Access-Control-Allow-Origin", new[] { (string)Request.Headers["Origin"] });
Response.Headers.Add("Access-Control-Allow-Headers", new[] { "Origin, X-Requested-With, Content-Type, Accept" });
Response.Headers.Add("Access-Control-Allow-Methods", new[] { "POST, OPTIONS" }); // new[] { "GET, POST, PUT, DELETE, OPTIONS" }
Response.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });
return NoContent();
}
[HttpPost("/find")]
public async Task<IActionResult> FindOptions([FromForm]Find_POSTModel model)
{
AllowCrossOrigin();
// your code...
}
private void AllowCrossOrigin()
{
Uri origin = null;
Uri.TryCreate(Request.Headers["Origin"].FirstOrDefault(), UriKind.Absolute, out origin);
if (origin != null && IsOriginAllowed(origin))
Response.Headers.Add("Access-Control-Allow-Origin", $"{origin.Scheme}://{origin.Host}");
}
当然,您可以按照自己的意愿实现IsOriginAllowed
private bool IsOriginAllowed(Uri origin)
{
const string myDomain = "mydomain.com";
const string[] allowedDomains = new []{ "example.com", "sub.example.com" };
return
allowedDomains.Contains(origin.Host)
|| origin.Host.EndsWith($".{myDomain}");
}
您可以在如何在单个端点上启用CORS以进行POST请求上找到更多详细信息。
app.UserCors("PolicyName");
移到了app.UseAuthorization();
之前,它就开始工作了!services.AddCors(options =>
{
options.AddPolicy("EnableCORS", bl =>
{
bl.WithOrigins(origins)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.Build();
});
});
..........................
app.UseAuthentication();
app.UseCors("EnableCORS");
.....
app.UseAuthorization();
我想针对我的特定情况提供一个具体的答案,我在本地测试API和客户端Web应用程序。我知道这是一个晚期条目,但CORS在dot net core中已经发生了很大变化,我认为像我这样的新手可能会从完整的帖子中受益。
对我来说,出现了两个问题。
首先,这将进入public void ConfigureServices(IServiceCollection services)
//lets add some CORS stuff
services.AddCors(options =>
{
options.AddDefaultPolicy(builder => {
builder.WithOrigins("http://localhost:3000",
"http://www.contoso.com");
builder.AllowAnyMethod();
builder.AllowAnyHeader();
builder.AllowCredentials();
});
});
然后,这个函数进入了public void Configure(IApplicationBuilder app, IWebHostEnvironment env)。
app.UseCors();