跨域問題怎么導致,以及原理這里不在贅述;
跨域問題的處理方案有多種,一是通過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的域名之后跨域問題就解決了
在此記錄一下這個簡單卻又一時半會沒有解決的問題