打开CORS源码,主要的是CorsMiddleware、CorsOptions、CorsPolicy、CorsPolicyBuilder、CorsResult、CorsService这几个类。
CorsPolicy:就是我们在Startup中的配置,如允许哪些域名可以跨域请求,允许哪些跨域请求方式,允许哪些额外的请求头,每个配置对应一个名称。
services.AddCors(options => options.AddPolicy("CorsTest", p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
CorsOptions:中包含一个字典IDictionary<string, CorsPolicy> PolicyMap,一个项目可能有过个Cors配置,所以这个CorsOptions就是通过配置名称管理这些配置的。
CorsPolicyBuilder:通过它来构造CorsPolicy。
CorsResult:是验证跨域过程得到的结果。如在第一次Options请求时,客户端发送了Origi::8089,服务器会返回Access-Control-Allow-Origin::8089,服务器验证:8089这个域名是否允许跨域,如果允许就将“:8089”这个值存储到CorsResult的AllowedHeaders中,在请求(第一次请求)返回的时候将这些加到HTTP请求头中。
CorsMiddleware:Cors中间件类,主要方法就是Invoke,每次HTTP请求都会调用这个方法。
public async Task Invoke(HttpContext context) {//判断HTTP请求头是否有Origin,由此判断是不是跨域请求 if (context.Request.Headers.ContainsKey(CorsConstants.Origin)) { var corsPolicy = _policy ?? await _corsPolicyProvider?.GetPolicyAsync(context, _corsPolicyName); if (corsPolicy != null) { var accessControlRequestMethod = context.Request.Headers[CorsConstants.AccessControlRequestMethod]; //如果是跨域请求 判断是不是第一次Options请求 if (string.Equals(context.Request.Method,CorsConstants.PreflightHttpMethod,StringComparison.OrdinalIgnoreCase) &&!StringValues.IsNullOrEmpty(accessControlRequestMethod)) { //判断是否允许当前请求跨域,根据HttpContext的内容和Cors配置 得到CorsResult,然后将CorsResult的内容添加到请求头中(看下面详细解释) ApplyCorsHeaders(context, corsPolicy); context.Response.StatusCode = StatusCodes.Status204NoContent; return; } else {// 执行第二次非Options请求 context.Response.OnStarting(state => { var (httpContext, policy) = (Tuple<HttpContext, CorsPolicy>)state; try { ApplyCorsHeaders(httpContext, policy); } catch (Exception exception) { _logger.FailedToSetCorsHeaders(exception); } return Task.CompletedTask; }, Tuple.Create(context, corsPolicy)); } } } await _next(context); } private void ApplyCorsHeaders(HttpContext context, CorsPolicy corsPolicy) { //通过HTTP上下文请求的数据和Cors配置 得到CorsResult 如在第一次Options请求时,客户端发送了Origi::8089,Access-Control-Resquest-Methods:GET 服务器会返回Access-Control-Allow-Origin::8089,Access-Control-Allow-Methods:GET 服务器验证:8089这个域名以GET请求方式是否允许跨域, 如果允许就将“:8089”这个值存储到CorsResult的AllowedHeaders中 将"GET"存储到CorsResult的AllowedMethods中 var corsResult = _corsService.EvaluatePolicy(context, corsPolicy); //将CorsResult中的值添加到相应头中的,返回到客户端 _corsService.ApplyResult(corsResult, context.Response); }
相对来说Cors源码还是比较简单的,很容易看懂。可以自己写一个项目,然后挂上源码单步调试。
总结