第十四节:Asp.Net Core 中的跨域解决方案(Cors、jsonp改造、chrome配置)
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了第十四节:Asp.Net Core 中的跨域解决方案(Cors、jsonp改造、chrome配置),小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含11506字,纯文字阅读大概需要17分钟。
内容图文
原文:第十四节:Asp.Net Core 中的跨域解决方案(Cors、jsonp改造、chrome配置)一. 整体说明
1. 说在前面的话
早在前面的章节中,就详细介绍了.Net FrameWork版本下MVC和WebApi的跨域解决方案,详见:https://www.cnblogs.com/yaopengfei/p/10340434.html ,由于在Core版本中,MVC和WebApi已经合并,所以在该章节中介绍Asp.Net Core中的跨域解决方案。
2. 背景
浏览器出于安全性考虑,禁止在网页上发出请求到不同的域的web页面进行请求,此限制称为同域策略。 同域策略可阻止恶意站点读取另一个站点中的敏感数据, 但有时候,你可能想要允许其他站点对您的应用程序进行跨域请求,所以有两套解决方案,分别是:CORS(跨域资源共享) 、 jsonp。
PS:有时候为了方便测试,可以直接配置一下Chrome浏览器,使其支持跨域请求。
3. 跨域资源共享(CORS)
它是一项 W3C 标准,主流浏览器都支持,原理是让服务器放宽同域策略,它很灵活,可以显式的控制允许哪些地址、哪种请求方式来进行跨域访问。
4. JSONP
简单的来说,它就是在json数据外面包了一层,它有一个很大的局限性,就是仅支持Get请求,如下JSON和JSONP的区别:
(1) json格式:
{
"id":123,
"name":"ypf"
}
(2) jsonp格式:在json外面包了一层
callback({
"id":123,
"name":"ypf"
})
其中callback取决于url传到后台是什么,它就叫什么。
5. 浏览器配置
有时候为了测试方便,我们可以直接配置一下Chrome浏览器,使其支持跨域。
二. 跨域资源共享
1. 说明
使用的程序集是【Microsoft.AspNetCore.Cors】,在Core Mvc中,默认已经包含了,无须再引入;他有两种作用形式,可以在Configure管道中UseMvc前进行全局拦截,也可以在以特性的形式作用于控制器 或 Action。
2. Cors策略详解
A. 设置允许的来源:WithOrigins 或 AllowAnyOrigin 如:WithOrigins("http://localhost:29492","http://localhost:5000")
B. 设置允许的方法:WithMethods 或 AllowAnyMethod 如:WithMethods("GET","PUT")
C. 设置允许的请求标头:WithHeaders 或 AllowAnyHeader
D. 设置公开响应标头:WithExposedHeaders
E. 允许请求中的凭据:AllowCredentials
PS:AddCors注册服务,AddDefaultPolicy注册默认策略、AddPolicy注册命名策略
3. 使用流程
流程一: 在ConfigureService先注册策略(默认策略或命名策略),然后可以在Configure管道中进行全局拦截 或者 以特性的形式作用于Controller或action。
流程二: 直接在Configure中配置相应的策略进行全局拦截,不需要在ConfigureService中注册任何代码。
4. 默认策略测试
(1). 前提
在Configure中通过AddDefultPolicy注册默认策略,策略内容:允许所有来源、所有方法、所有请求标头、允许请求凭据。代码如下:
1publicvoid ConfigureServices(IServiceCollection services) 2 { 3 services.Configure<CookiePolicyOptions>(options => 4 { 5// This lambda determines whether user consent for non-essential cookies is needed for a given request. 6 options.CheckConsentNeeded = context => true; 7 options.MinimumSameSitePolicy = SameSiteMode.None; 8 }); 910//注册跨域请求服务11 services.AddCors(options => 12 { 13//注册默认策略14 options.AddDefaultPolicy(builder => 15 { 16 builder.AllowAnyOrigin() 17 .AllowAnyMethod() 18 .AllowAnyHeader() 19 .AllowCredentials(); 20 }); 21 }); 22 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); 23 }
(2). 测试1-全局拦截
在ConfigureService中(app.UseMvc前)通过app.UseCors();注册默认策略,然后在前端访问Test1方法,正常访问。
PS:Test1方法要注释掉cors特性后再测试。
1publicvoid Configure(IApplicationBuilder app, IHostingEnvironment env) 2 { 3if (env.IsDevelopment()) 4 { 5 app.UseDeveloperExceptionPage(); 6 } 7else 8 { 9 app.UseExceptionHandler("/Home/Error"); 10 } 1112 app.UseStaticFiles(); 13 app.UseCookiePolicy(); 1415//全局配置跨域(一定要配置在 app.UseMvc前) 16//1. 默认策略17 app.UseCors(); 1819 app.UseMvc(routes => 20 { 21 routes.MapRoute( 22 name: "default", 23 template: "{controller=Home}/{action=Index}/{id?}"); 24 }); 25 }
1///<summary>2/// 默认策略 3///</summary>4///<returns></returns>5 [HttpPost] 6publicstring Test1() 7 { 8return"ypf001"; 9 }
1//1. 测试cors默认策略2 $(‘#j_btn1‘).click(function () { 3 $.post("http://localhost:29492/Home/Test1", {}, function (data) { 4 alert(data); 5 }); 6 });
(3). 测试2-特性作用
在Test1方法上增加特性[EnableCors],然后进行测试,正常访问。
PS:ConfigureService中全局拦截要注释掉再测试
1///<summary> 2/// 默认策略 3///</summary> 4///<returns></returns> 5 [EnableCors] 6 [HttpPost] 7publicstring Test1() 8 { 9return"ypf001"; 10 }
5. 命名策略测试
(1). ConfigureService中策略的注册代码
1publicvoid ConfigureServices(IServiceCollection services) 2 { 3 services.Configure<CookiePolicyOptions>(options => 4 { 5// This lambda determines whether user consent for non-essential cookies is needed for a given request. 6 options.CheckConsentNeeded = context => true; 7 options.MinimumSameSitePolicy = SameSiteMode.None; 8 }); 910//注册跨域请求服务11 services.AddCors(options => 12 { 13//注册一个名字为“AnotherPolicy”新策略14 options.AddPolicy("AnotherPolicy", builder => 15 { 16 builder.WithOrigins("http://localhost:29553", "http://localhost:5001") //多个地址通过"逗号"隔开17 .WithMethods("GET","PUT") 18 .WithHeaders(Microsoft.Net.Http.Headers.HeaderNames.ContentType, "Authorization") 19 .AllowCredentials(); 2021 }); 2223 }); 24 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); 25 }
(2). Configure全局拦截代码 或者 作用于Action的代码 (二者选其一即可)
全局拦截:
1publicvoid Configure(IApplicationBuilder app, IHostingEnvironment env) 2 { 3if (env.IsDevelopment()) 4 { 5 app.UseDeveloperExceptionPage(); 6 } 7else 8 { 9 app.UseExceptionHandler("/Home/Error"); 10 } 11 app.UseStaticFiles(); 12 app.UseCookiePolicy(); 1314//全局配置跨域(一定要配置在 app.UseMvc前) 15//2. 命名策略16 app.UseCors("AnotherPolicy"); 1718 app.UseMvc(routes => 19 { 20 routes.MapRoute( 21 name: "default", 22 template: "{controller=Home}/{action=Index}/{id?}"); 23 }); 24 }
作用于action
1///<summary> 2/// 命名策略 3///</summary> 4///<returns></returns> 5 [EnableCors("AnotherPolicy")] 6 [HttpPost] 7publicstring Test2() 8 { 9return"ypf002"; 10 }
(3). 前端测试代码
1//2. 测试cors命名策略 2 $(‘#j_btn2‘).click(function () { 3 $.ajax({ 4 url: ‘http://localhost:29492/Home/Test2‘, 5 type: "Post", 6 xhrFields: { 7//发送跨域请求凭据 8 withCredentials: true 9 }, 10 cache: false, 11 data: {}, 12 beforeSend: function (request) { 13//在请求报文头中加入Authorization 目的是让请求为非简单请求14 request.setRequestHeader("Authorization", "Bearer 071899A00D4D4C5B1C41A6B0211B9399"); 15 }, 16 success: function (data) { 17 alert(data); 18 } 19 }); 20 });
6. 直接Configure全局配置测试
直接在Configure管道中配置策略,默认允许所有,注释掉ConfigureService中的所有策略和Test1、Test2方法上的特性, 仍然可以正常访问,测试通过。
1publicvoid Configure(IApplicationBuilder app, IHostingEnvironment env) 2 { 3if (env.IsDevelopment()) 4 { 5 app.UseDeveloperExceptionPage(); 6 } 7else 8 { 9 app.UseExceptionHandler("/Home/Error"); 10 } 1112 app.UseStaticFiles(); 13 app.UseCookiePolicy(); 1415//全局配置跨域(一定要配置在 app.UseMvc前) 16//3. 直接配置策略,不需在Configure中注册任何代码了17 app.UseCors(options => 18 { 19 options.AllowAnyOrigin() 20 .AllowAnyMethod() 21 .AllowAnyHeader() 22 .AllowCredentials(); 23 }); 2425 app.UseMvc(routes => 26 { 27 routes.MapRoute( 28 name: "default", 29 template: "{controller=Home}/{action=Index}/{id?}"); 30 }); 31 }
特别注意:
在core 2.x版本,AllowAnyOrigin()和AllowCredentials()可以共存,在3.x版本,不能共存。
三. JSONP
1. 原始的jsonp模式
在Asp.Net Core中支持,在.Net版本的webapi中是不支持,即在方法中声明一个接受参数与前端JSONP位置传递过来的进行对应,然后将数据进行包裹返回,$"{myCallBack}({xjs})"。以JQuery的Ajax请求为例,可以指定JSONP的名称,如下面代码指定为:myCallBack,如果省略,JSONP的名称则为:callback。
特别注意:凡是JSONP请求,GET请求地址的第一个参数则为JSONP位置配置的名称,如:http://localhost:29492/Home/GetInfor2?myCallBack=jQuery341001790888637311383_1564124488832&userName=ypf&_=1564124488833
服务器端代码:
1///<summary> 2/// 原始的JSONP模式,支持 3///</summary> 4///<param name="callBack"></param> 5///<param name="userName"></param> 6///<returns></returns> 7 [HttpGet] 8 9publicdynamic GetInfor1(string myCallBack, string userName) 10 { 11var data = new12 { 13 id = userName + "001", 14 userName = userName 15 }; 16string xjs = JsonConvert.SerializeObject(data); 17return $"{myCallBack}({xjs})"; 18 }
前端代码:
1 $(‘#j_jsonp1‘).click(function () { 2 $.ajax({ 3 url: ‘http://localhost:29492/Home/GetInfor1‘, 4 type: "get", 5 dataType: "jsonp", 6//需要和服务端回掉方法中的参数名相对应 7//注释掉这句话默认传的名称叫callback 8 jsonp: "myCallBack", 9 cache: false, 10 data: { userName: "ypf" }, 11 success: function (data) { 12 console.log(data); 13 alert(data.id + "," + data.userName); 14 } 15 }); 16 });
2. 利用过滤器判断请求来决定是否跨域
(1) 背景
想实现服务器端方法正常写,该返回什么就返什么,如果是JSONP请求,则返回JSONP格式,如果是普通请求,则返回不同格式。
(2) 原理
如果是jsonp请求的,如同下面这个地址:http://localhost:29492/Home/GetInfor2?myCallBack=jQuery341001790888637311383_1564124488832&userName=ypf&_=1564124488833, 第一个参数为myCallBack,如果有这个参数则证明是jsonp请求,需要拿到它的值;反之如果没有这个参数,则是普通请求,需要配置跨域策略了,才能拿到值。
在过滤器中判断,如果是jsonp请求,则将数据进行包裹进行返回,如果是普通请求,则直接返回,然后把过滤器以特性[IsJsonpCallback]形式作用在GetInfor2方法上。
过滤器代码:
1publicclass IsJsonpCallbackAttribute: ActionFilterAttribute 2 { 3privateconststring CallbackQueryParameter = "myCallBack"; 4publicoverridevoid OnActionExecuted(ActionExecutedContext context) 5 { 6 7string text = context.HttpContext.Request.QueryString.Value; 8string[] arrys = text.Split(‘&‘); 9if (arrys[0].Contains(CallbackQueryParameter)) 10 { 11var myCallBackValue = arrys[0].Split(‘=‘)[1]; 12var result = $"{myCallBackValue}({((ObjectResult)context.Result).Value})"; 13 context.HttpContext.Response.WriteAsync(result); 14 } 1516base.OnActionExecuted(context); 17 } 18 }
服务器端代码:
1///<summary> 2/// 改造后的Jsonp(请求是Jsonp格式,则返回jsonp格式,反之普通格式) 3///</summary> 4///<param name="callBack"></param> 5///<param name="userName"></param> 6///<returns></returns> 7 [HttpGet] 8 [IsJsonpCallback] 910publicdynamic GetInfor2(string userName) 11 { 12var data = new13 { 14 id = userName + "001", 15 userName = userName 16 }; 17string xjs = JsonConvert.SerializeObject(data); 18return $"{xjs}"; 19 }
前端代码:
1//2. 利用过滤器改造-jsonp请求 2 $(‘#j_jsonp2‘).click(function () { 3 $.ajax({ 4 url: ‘http://localhost:29492/Home/GetInfor2‘, 5 type: "get", 6 dataType: "jsonp", 7//需要和服务端回掉方法中的参数名相对应 8//注释掉这句话默认传的名称叫callback 9 jsonp: "myCallBack", 10 cache: false, 11 data: { userName: "ypf" }, 12 success: function (data) { 13 console.log(data); 14 alert(data.id + "," + data.userName); 15 } 16 }); 17 }); 18//3. 利用过滤器改造-普通请求19 $(‘#j_jsonp21‘).click(function () { 20 $.ajax({ 21 url: ‘http://localhost:29492/Home/GetInfor2‘, 22 type: "get", 23 dataType: "json", 24 cache: false, 25 data: { userName: "ypf" }, 26 success: function (data) { 27 console.log(data); 28 alert(data.id + "," + data.userName); 29 } 30 }); 31 });
3. 利用程序集【WebApiContrib.Core.Formatter.Jsonp】改造
GitHub地址:https://github.com/WebApiContrib/WebAPIContrib.Core/tree/master/src/WebApiContrib.Core.Formatter.Jsonp
通过Nuget引入上面程序集,在ConfigureServices中的AddMvc中,书写代码 option => option.AddJsonpOutputFormatter(),即可实现JSONP请求返回JSONP格式,普通请求返回不同格式, 默认情况下回调参数为“callback”,也可以手动配置:option =>option.AddJsonpOutputFormatter(mvcOption.OutputFormatters.OfType<JsonOutputFormatter>().FirstOrDefault(), "myCallBack")
默认回调参数配置的代码:
1 services.AddMvc( 2//不写参数的话,走的是默认回调参数 callback3 option => option.AddJsonpOutputFormatter() 4 ).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
命名回调参数配置的代码:
1 MvcOptions mvcOption = new MvcOptions(); 2 services.AddMvc( 3//配置JSONP的方案二,回调参数配置为myCallBack4 option =>option.AddJsonpOutputFormatter(mvcOption.OutputFormatters.OfType<JsonOutputFormatter>().FirstOrDefault(), "myCallBack")6 ).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
通过上面的代码配置,即可实现JSONP请求返回JSONP格式,普通请求返回不同格式。(原理去github上看代码)
四. Chrome浏览器配置
1. 前提
注释掉所有策略、特性,通过下面的步骤设置Chrome浏览器的属性,使其支持跨域。
2. 配置步骤
(1).在电脑上新建一个目录,例如:C:\MyChromeDevUserData
(2).在Chrome根目录中找到exe程序,在其属性页面中的目标输入框里加上 --disable-web-security --user-data-dir=C:\MyChromeDevUserData,其中--user-data-dir的值就是刚才新建的目录。
如下图:
配置内容为:"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-web-security --user-data-dir=C:\MyChromeDevUserData,--user-data-dir
(3).点击应用和确定后关闭属性页面,并打开chrome浏览器。再次打开chrome,发现有“--disable-web-security”相关的提示,如下图:,说明chrome可以正常跨域工作了。
3. 测试
(1). 服务器端方法 和 前端请求代码 如下:
1///<summary>2/// 不进行任何配置,通过配置浏览器进行跨域 3///</summary>4///<returns></returns>5publicstring TestNoConfig() 6 { 7return"ypfTestNoConfig"; 8 }
1//1. 配置浏览器进行跨域2 $(‘#j_brower‘).click(function () { 3 $.post("http://localhost:29492/Home/TestNoConfig", {}, function (data) { 4 alert(data); 5 }); 6 });
(2). 先用普通浏览器进行请求,请求不通,如下图:
(3). 再用配置好跨域的chrome进行请求,请求通了,如下图:
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 本人才疏学浅,用郭德纲的话说“我是一个小学生”,如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。
原文:https://www.cnblogs.com/lonelyxmas/p/12927574.html
内容总结
以上是互联网集市为您收集整理的第十四节:Asp.Net Core 中的跨域解决方案(Cors、jsonp改造、chrome配置)全部内容,希望文章能够帮你解决第十四节:Asp.Net Core 中的跨域解决方案(Cors、jsonp改造、chrome配置)所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。