跨域问题怎么导致,以及原理这里不在赘述;
跨域问题的处理方案有多种,一是通过ngix配置解决;二是服务端程序解决
这里主要说一下.net core程序的处理方法:
首先在ConfigureServices里面注册跨域Policy
services.AddCors(options => { options.AddPolicy(AbpBaseWebCosr, policy => { policy .WithOrigins(_appConfig.CorUrls) .AllowAnyHeader() .AllowAnyMethod(); }); });
然后在中间件里面使用跨域处理中间件即可,这里可以使用框架自带的中间件也可以自定义中间件:
框架自带中间件:
//跨域 app.UseCors(AbpBaseWebCosr);
自定义中间件:
中间件类:
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);
之后就可以解决跨域问题;
但是在过程中我始终遇到了一个报错 No ‘Access-Control-Allow-Origin‘ header is present on the requested resource.以及mutille的报错,跨域配置没有生效,看了很久都没有结论,不管是框架自带的中间件还是自定义中间件都不行,最后在查看浏览器的请求头以及响应的头做了对比之后终于发现了问题;
在浏览器的请求头中会有两个字段标示 请求来源:Origin和Referer,而且从目前的现象来看,当同时都有的时候,框架系统会优先去Referer的域名来做判断;
恰好在两个请求来源中两个域名有轻微差别:
一个多了一个斜线,一个没有,而在我们代码WithOrigin()配置的时候,恰好没有这个斜线,就导致跨域一直失效;
所以最后配置了Referer的域名之后跨域问题就解决了
在此记录一下这个简单却又一时半会没有解决的问题