已阻止跨源请求:CORS 头缺少 ‘Access-Control-Allow-Origin’-超详细

-- 请求&已阻止跨源请求:CORS 头缺少 ‘Access-Control-Allow-Origin‘-(js,axios,vue,react等)
【官网】:

应用场景

市面上浏览器出于安全性考虑,禁止在网页上发出请求到不同的域的web页面进行请求,此限制称为同域策略。 同域策略可阻止恶意站点读取另一个站点中的敏感数据, 但有时候,你可能想要允许其他站点对您的应用程序进行跨域请求,目前有两套解决方案,分别是:CORS(跨域资源共享) 、 jsonp。

基础资源

前端跨域访问依赖后端设置

使用须知

1)Core版本中,MVC和WebApi已经合并,所以在该章节中介绍Asp.Net Core中的跨域解决方案。 2)请结合企业产品或平台的安全要求,请勿盲目放开准许跨域。应以最小限度放开。

配置步骤

【方案1-前端使用jsonp+后端输出callback回调】

 <前端代码示例>
                $.ajax({
                    url: ‘http://config.net.cn/Example/TestApi‘,
                    type: "get",
                    dataType: "jsonp",
                    //需要和服务端回掉方法中的参数名相对应
                    //注释掉这句话默认传的名称叫callback
                    jsonp: "CallBackForTest",
                    cache: false,
                    data: { userName: "user" },
                    success: function (data) {
                        console.log(data);
                        alert(data.id + "," + data.userName);
                    }
                });
<后端代码示例>
        /// <summary>
        /// 原始的JSONP模式,支持(asp.net core支持,asp.net web api不支持)
        /// </summary>
        /// <param name="CallBackForTest"></param>
        /// <param name="userName"></param>
        /// <returns></returns>
        [HttpGet] public dynamic GetInfor1(string CallBackForTest, string userName)
        {
            var data = new
            {
                id = userName + "01",
                userName = userName
            };
            string callbackParams = JsonConvert.SerializeObject(data);
            return $"{CallBackForTest}({callbackParams })";
        }


方案2-服务端输出时设置header:Access-Control-Allow-Origin

header("Access-Control-Allow-Origin: *");  

注1: 在设置header的具体过程,各个语言稍有不同,其中值*最好设置为具体的域名,比如:header("Access-Control-Allow-Origin: http://config.net.cn");  

另外输出页面的话,可以设置:


<meta http-equiv="Access-Control-Allow-Origin" content="*">   
注2:本质上也是设置了header头的属性。
【方案3-cors命名策略的全局拦截或action特性指定】
<step1:ConfigureService中策略的注册代码>
public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            //注册跨域请求服务
            services.AddCors(options =>
            {
                //注册一个名字为“DefaultPolicy”新策略
                options.AddPolicy("DefaultPolicy", builder =>
                {
                    builder.WithOrigins("http://localhost:1001", "http://localhost:1002")  //多个地址通过"逗号"隔开
                          .WithMethods("GET","PUT")
                          .WithHeaders(Microsoft.Net.Http.Headers.HeaderNames.ContentType, "Authorization")
                          .AllowCredentials();

                });

            });
         services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }
[注]补充:在core 2.x版本,AllowAnyOrigin()和AllowCredentials()可以共存,在3.x版本,不能共存,不能共存时需要指定具体的域名。 <step2:Configure全局拦截代码  或者  作用于Action的代码 >
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }
            app.UseStaticFiles();
            app.UseCookiePolicy();

            //全局配置跨域(一定要配置在 app.UseMvc前)
            //2. 命名策略
            app.UseCors("DefaultPolicy");

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
[单个controller/action上指定]
            /// <summary>
        /// 命名策略
        /// </summary>
        /// <returns></returns>
        [EnableCors("DefaultPolicy")]
        [HttpPost]
        public string Test()
        {
            return "来自config.net.cn上的跨域问题解决办法分享";
        }




【方案4-服务端http服务程序的配置,例如:Apache等】

<apache中的设置>

在httpd.conf中,取消LoadModule headers_module modules/mod_headers.so前的注释

在<VirtualHost>中添加以下内容

Apache set ‘Access-Control-Allow-Origin’ *

重启apache即可.



常见问题

  • 服务端设置 Access-Control-Allow-Origin为 *依然提示跨域
    【解决方案】js客户端访问时设置了xhr.withCredentials = true时服务端必须指定具体的域名而不是*,否则无法访问

快速入门

【H5场景下cors跨域请求的封装】

function createCORSRequest(method, url) {

  var xhr = new XMLHttpRequest();
  if ("withCredentials" in xhr) {
    // 此时即支持CORS的情况
    // 检查XMLHttpRequest对象是否有“withCredentials”属性
    // “withCredentials”仅存在于XMLHTTPRequest2对象里
    xhr.open(method, url, true);
 
  } else if (typeof!= "undefined") {
 
    // 否则检查是否支持XDomainRequest,IE8和IE9支持
    // XDomainRequest仅存在于IE中,是IE用于支持CORS请求的方式
    xhr = new XDomainRequest();
    xhr.open(method, url);
 
  } else {
 
    // 否则,浏览器不支持CORS
    xhr = null;
 
  }
  return xhr;
}
 
var xhr = createCORSRequest(‘GET‘, url);
if (!xhr) {
  throw new Error(‘CORS not supported‘);
}

参考资料