


前端请求接口报错:ccess to XMLHttpRequest at ‘xxx’ from origin ‘null’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
当然这个可以在前端解决,比如前端使用代理,如果要在后端解决的话可以使用如下的方法
ConfigureServices中添加
services.AddCors(a =>
a.AddPolicy("any",
ap => ap.AllowAnyOrigin().//允许任何来源的主机访问
AllowAnyHeader().//允许任何标头(这个最好写到AllowAnyMethod上面去)
AllowAnyMethod()//允许任何方法访问
));
当然也可以使用WithOrigins限制具体的Ip地址等等。比如把白名单ip配置到配置文件,在从配置文件中读取出来使用WithOrigins加载
.WithOrigins(appConfig.CorUrls)
AllowAnyHeader()这个最好写到AllowAnyMethod上面去。不然可能会多出来204的请求出来(HTTP返回码,指服务器成功处理了请求,但没返回任何内容)。当然其实影响不大。
Configure中添加
app.UseCors("any");
注意app.UseCors(“any”);不要写到app.UseEndpoints下边去,无法解决跨域问题的!比如下面这种情况就是写到app.UseEndpoints下面去了,还是会出现跨域。
因为中间件是顺序执行的,我估计因为app.UseEndpoints里边使用了mvc的东东,比如Controller,估计在处理Controller中的中间件也有相关的跨域验证,验证不过就直接返回跨域错误了,根本到不了下面的app.UseCors(“any”)了。就像路由的顺序要特别注意一样,中间件也是,都是按顺序执行的,如果前面就断路返回了,后面根据没有几乎执行了
这个跨域处理的中间件其实也可以自己来实现逻辑
自定义跨域处理中间件可以更加灵活的实现跨域
public class MyCorsMiddleware
{
private readonly RequestDelegate _next;
private readonly ICorsService _corsService;
private readonly ICorsPolicyProvider _corsPolicyProvider;
private readonly CorsPolicy _policy;
private readonly string _corsPolicyName;
public MyCorsMiddleware(RequestDelegate next, ICorsService corsService, CorsPolicy policy)
{
_next = next;
_corsService = corsService;
_policy = policy;
}
public MyCorsMiddleware(RequestDelegate next, ICorsService corsService, ICorsPolicyProvider corsPolicyProvider)
{
_next = next;
_corsService = corsService;
_corsPolicyProvider = corsPolicyProvider;
}
public MyCorsMiddleware(RequestDelegate next, ICorsService corsService, ICorsPolicyProvider corsPolicyProvider, string corsPolicyName)
{
_next = next;
_corsService = corsService;
_corsPolicyProvider = corsPolicyProvider;
_corsPolicyName = corsPolicyName;
}
public async Task Invoke(HttpContext context)
{
if (context.Request.Headers.ContainsKey("Origin"))
{
var corsPolicy = _policy ?? await _corsPolicyProvider?.GetPolicyAsync(context, _corsPolicyName);
if(corsPolicy != null)
{
var corsResult = _corsService.EvaluatePolicy(context, corsPolicy);
_corsService.ApplyResult(corsResult, context.Response);
var accessControlRequestMethod = context.Request.Headers["Access-Control-Request-Mechod"];
if(string.Equals(
context.Request.Method,
"OPTIONS",
StringComparison.OrdinalIgnoreCase) &&
!StringValues.IsNullOrEmpty(accessControlRequestMethod))
{
context.Response.StatusCode = 204;
return;
}
}
if(context.Request.Headers.TryGetValue("Origin", out var origins))
{
string[] tmp = origins.ToString().Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
if (tmp.Length == 2 || tmp.Length == 3)
{
if (tmp[1].Trim() == "//uni.test.com" || tmp[1].Trim() == "//localhost")
{
context.Response.Headers.TryAdd("Access-Control-Allow-Origin", origins);
context.Response.Headers.TryAdd("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
context.Response.Headers.TryAdd("Access-Control-Allow-Methods", "POST,OPTIONS,GET");
context.Response.Headers.TryAdd("Access-Control-Allow-Credentials", "true");
}
}
}
}
await _next(context);
}
}
注册中间件
public static class MyCorsMiddleWareExstension
{
public static IApplicationBuilder UseMyCorsMiddleWare(this IApplicationBuilder builder, string policyName)
{
return builder.UseMiddleware<MyCorsMiddleware>(policyName);
}
}
使用中间件:
app.UseMyCorsMiddleWare(AbpBaseWebCosr);
其他方法可以考虑给某个接口单独设置Response的Headers以及EnableCors特性等。
比如给某个接口的response手动添加一个Access-Control-Allow-Origin
Response.Headers.Add("Access-Control-Allow-Origin", "*");
当然使用这种自己手动添加的方式,也要注意顺序问题,如果顺序不对,跨域的不允许在中间件中默认就已经处理了,根据就没有机会到我们自己写的这里来。虽然跨域的原理是这样,写了就应该支持跨域了,但是如果因为顺序问题,根据就没有机会执行到我们自己实现跨域逻辑这里来,也是没有用的!
更多信息添加:
[HttpGet]
public IEnumerable<string> Get()
{
string userNr = Request.Headers["userNr"];
//Response.Headers.Add("Content-Type", "application/json");
Response.Headers.Add("Access-Control-Allow-Origin", "*");
Response.Headers.Add("Access-Control-Allow-Headers", "*");
Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,OPTIONS,PUT,DELETE");
//Response.Headers.Add("Access-Control-Allow-Credentials", "true");
//Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type");
//Response.Headers.Add("Access-Control-Allow-Headers", "*,Content-Type,accessToken,Authorization");
//Response.Headers.Add("Content-Type", "*");
return new string[] { "value6", "value6" };
}
还可以考虑一下使用EnableCors特性
[EnableCors("any")]
如果使用了nginx你可能还需要在nginx配置跨域
location / {
if ($request_method = OPTIONS ) {
add_header Content-Type *;
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'POST, GET, OPTIONS, PUT, DELETE';
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Headers '*,Content-Type,accessToken,Authorization';
return 200;
}
}
像是允许具体的域名跨域请求可以类似这种配置
http:
headers:
Access-Control-Allow-Origin: ['http://registry.example.com']
Access-Control-Allow-Credentials: [true]
Access-Control-Allow-Headers: ['Authorization', 'Accept']
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS'] # Optional
欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739。有需要软件开发,或者学习软件技术的朋友可以和我联系~(Q:815170684)