.net core 跨域,.net5.0 跨域 电脑版发表于:2020/6/16 15:20 **前端请求接口报错:**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) ``` tn2> AllowAnyHeader()这个最好写到AllowAnyMethod上面去。不然可能会多出来204的请求出来(HTTP返回码,指服务器成功处理了请求,但没返回任何内容)。当然其实影响不大。 ### Configure中添加 ``` app.UseCors("any"); ``` tn> 注意app.UseCors("any");不要写到app.UseEndpoints下边去,无法解决跨域问题的!比如下面这种情况就是写到app.UseEndpoints下面去了,还是会出现跨域。 ![](https://img.tnblog.net/arcimg/aojiancc2/574a0edc8b524ad0aa4d237ee7310ac9.png) tn2>因为中间件是顺序执行的,我估计因为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", "*"); ``` ![](https://img.tnblog.net/arcimg/aojiancc2/0c9f43914e0a481bb7afe7b8deec24aa.png) tn6>当然使用这种自己手动添加的方式,也要注意顺序问题,如果顺序不对,跨域的不允许在中间件中默认就已经处理了,根据就没有机会到我们自己写的这里来。虽然跨域的原理是这样,写了就应该支持跨域了,但是如果因为顺序问题,根据就没有机会执行到我们自己实现跨域逻辑这里来,也是没有用的! **更多信息添加:** ``` [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 ```