由于项目中需要实时消息,所以就使用了ASP.NET(Core) SignalR
实时通讯库。因为业务服务与通讯服务是独立的,所以涉及到跨域的问题, 浏览器抛出的异常非常明显,这个是明显跨域相关内容。 报错信息如下:
Access to XMLHttpRequest at ‘http://192.168.2.13:5005/api/v1/commommessage/messageHub/negotiate’ from origin ‘http://127.0.0.1:5500’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
CORS
(跨域资源共享)是一种W3C标准,允许服务器放宽同源策略。使用CORS
,服务器可以在显式允许某些跨域请求时拒绝其他跨域请求。CORS
是相比其他跨域技术(比如JSONP
)更安全、更灵活。
ASP.NET Core跨域问题需要再 StartUp.cs
文件中进行相关配置。
ConfigureServices
方法增加内容
services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
builder.AllowAnyMethod()
.AllowAnyHeader()
.AllowAnyOrigin()
.AllowCredentials();
}));
完整的ConfigureServices
方法示例如下:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
builder.AllowAnyMethod()
.AllowAnyHeader()
.AllowAnyOrigin()
.AllowCredentials();
}));
services.AddMvc(options => { options.Filters.Add(); })
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
//全局配置Json序列化处理
.AddJsonOptions(options =>
{
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
})
.AddFluentValidation();
services.AddSignalR();
return services.AutofacServiceProvider();
}
在Configure
方法中添加
app.UseCors("CorsPolicy");
完整Configure
方法示例:
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory,
IOptions config)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
if (env.IsProduction())
{
//注册服务到consul
app.UseConsul();
using (HttpClient client = new HttpClient())
{
StringContent content = new StringContent(JsonConvert.SerializeObject(config.Value.RegisterParams));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage message = client.PostAsync(config.Value.Server.Address, content).Result;
};
}
app.UseCors("CorsPolicy");
loggerFactory.AddNLog();
env.ConfigureNLog("nlog.config");//读取Nlog配置文件
app.UseSignalR(routes =>
{
routes.MapHub("/api/v1/examinations/messageHub");
});
app.UseMvc();
}
特别注意:app.UseCors()
必须放在app.UseMvc()
之前。
本以为这就算完了,但是万万没想到啊,依然没有什么用。浏览器控制台错误依然存在,.net core也提示了相关警告信息,差点就忘了现在使用.net core 版本和以前不一样了。
The CORS protocol does not allow specifying a wildcard (any) origin and credentials at the same time. Configure the policy by listing individual origins if credentials needs to be supported.
目前使用的是ASP.NET CORE 2.1, 其Cors
组件已经升级,出于安全考虑必须明确要允许的内容。 这是安全的一部分,你不能这样做。 如果要允许凭据,则Access-Control-Allow-Origin
不能使用*
。 您必须指定确切的协议+域+端口。
这个问题其实也很好解决,只需要给予一个可信列表即可。修改内容如下:
services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
builder.WithOrigins(new string[] { "http://127.0.0.1:5500" })
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
}));
如果真的就不想做任何限制,其实也是有办法的。只需要将AllowAnyOrigin
替换为SetIsOriginAllowed(_ => true)
就可以解决。
services.AddCors(options => options.AddPolicy("CorsPolicy",
builder =>
{
builder.AllowAnyMethod()
.SetIsOriginAllowed(_ => true)
.AllowAnyHeader()
.AllowCredentials();
}));
除了前面的两个方法以外,其实还可以自定义中间件。添加Cors
处理类。如下:
public class CorsMiddleware
{
private readonly RequestDelegate next;
public CorsMiddleware(RequestDelegate next)
{
this.next = next;
}
public async Task Invoke(HttpContext context)
{
if (context.Request.Headers.ContainsKey(CorsConstants.Origin))
{
context.Response.Headers.Add("Access-Control-Allow-Origin", context.Request.Headers["Origin"]);
context.Response.Headers.Add("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS,HEAD,PATCH");
context.Response.Headers.Add("Access-Control-Allow-Headers", context.Request.Headers["Access-Control-Request-Headers"]);
context.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
if (context.Request.Method.Equals("OPTIONS"))
{
context.Response.StatusCode = StatusCodes.Status200OK;
return;
}
}
await next(context);
}
}
在Configure
方法中添加如下内容即可
app.UseMiddleware<CorsMiddleware>();