欢迎大家阅读《朝夕Net社区技术专刊》
我们致力于.NetCore的推广和落地,为更好的帮助大家学习,方便分享干货,特创此刊!很高兴你能成为忠实读者,文末福利不要错过哦!
01
PART
CoreWebApi的调用
1.在Core MVC下建立WebApi—CrossDomainController控制器下的GetCrossDomainData api,如图1所示;启动后通过浏览器调用正常如图2;
图1
图2
2.那么试试Ajax调用试试呢?如图3,如果请求到,就把结果放到div 中去;那运行的时候,不仅没有获取到数据,而且还报错了如图4.
图3
图4
那么这里的问题就是浏览器的同源策略,引发的跨域问题;下面将把这个问题的根本缘由给大家做一下说明.
02
PART
浏览器同源策略
什么是同源策略?同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,请明确:他是浏览器的安全约定。所谓的同源,指的是协议,域名,端口相同。浏览器处于安全方面的考虑,只允许本域名下的接口交互,不同源的客户端脚本,在没有明确授权的情况下,不能读写对方的资源。
设想这样一种情况:A网站是一家银行,用户登录以后,又去浏览其他的网站,如果其他网站可以读取A网站的Cookie,会发生什么?很显然,如果Cookie包含隐私(比如存款总额),这些信息就会泄漏。更可怕的是Cookie往往用来保存用于的登录状态,如果用户没有退出登录,其他网站就可以冒充用户为所欲为,因为浏览器同时还规定,提交表单不受同源策略的限制。由此可见,同源策略是必须的。如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问;如图5。
图5
那么上面我们在调用的时候就是因为这个问题、Ajax的脚本,和Api非同源;Ajax请求Api的时候,违背了浏览器的这个约定,所以不能用;其实Ajax在请求的时候,是能够请求到Api的,Api也返回了数据;却因为浏览的同源要求,而报错了;下面给大家证明一下:运行Api:Api打断点:测试起来。。。如图6 、图7所示;
图6
断点能进来
图7
但是就是报错,浏览器限制了;不能用;
以上描述的就是浏览器的同源策略 在非同源的情况下使用脚本调用Api会报错的;这就是所谓的跨域问题。
03
PART
如何解决跨域问题?
首先来分析一下出这个问题的原因;是因为浏览器的约定而出现的;那么如果我不使用非同源的脚本来调用呢?是可以的;定义一个Api 模拟Http请求去请求这个非同源的Api;
第一步:定义定义Api 模拟http请求:
我这里是另外又建立了一个项目:模拟http请求;调用这个Api,让这个后台的Api再去调用非同源的Api-- GetCrossDomainData
第二步:运行起来:
包括运行GetCrossDomainDataApi所在的项目;命令启动:dotnet Zhaoxi.Core.WebApi.dll --urls="http://*:8004" -- ip="127.0.0.1" --port= 8004;监控的端口号为8004;
然后启动调用GetCrossDomainDataApi的项目:试试看;如图8 图9
图8
命令启动了;监控的是8004端口
图9
调用TestApi 方法;让其执行InvokeApi方法,去调用
GetCrossDomainDataApi;
执行结果:如图10
图10
结果拿到了;避开了跨域问题;
那就是解决跨域问题的第一种策略:通过后台模拟Http请求,去调用Api,可以避开跨域问题;因为跨域是因为浏览器的同源引发的、不使用非同源的脚本去调用时Ok的;是不是很棒?
这是第一种策略:我们再往下分析;看看刚刚在调用的时候,报的错是什么?
Access to XMLHttpRequest at 'http://localhost:64304/api/CrossDomain/GetCrossDomainData' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
其实这个提示也很明确哦:提示请求上下文不存在“Access-Control-Allow-origin” 头信息;那是不是加上这个头信息就Ok了呢?来试试看:请看下图11;仅仅只是加了一段代码。
图11
再来试试。。。来运行起来!还是命令启动:dotnet Zhaoxi.Core.WebApi.dll --urls="http://*:8004" -- ip="127.0.0.1" --port= 8004 如图12
图12
Ajax调用:如图13 图14
图13
图14
这其实也是解决跨域的常用方法;就是在浏览器直接标记告诉调用者,Ok,我这个Api是允许你跨域访问的;仅此而已,是不是很简单?
不过如果用这种方法来支持跨域,难道在每个方法中都标记:HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");这句话吗?这很显然很不爽;
还记不记得,前面的文章中写了ActionFilter的使用?在这里是不是很适合?
OK 马上给你实现一个,定义个Filter,标记在方法上,如果需要所有Api 都跨域的话,全局注册即可;请看下图15 图16
图15
图16
测试结果如下:没毛病,完美解决问题;如图17
图17
以上也是解决跨域问题的常用策略;是通过在服务器指定当前Api允许跨域访问的方式;
下面我将继续给大家分享一种解决跨域问题的方式:其实在AspNetCore 中已经有支持跨域的Api;听我慢慢道来;
第一步:Nuget引入程序包:Microsoft.AspNetCore.Cors.dll
第二步:注册跨域服务:如图18
图18
第三步:use 跨域中间件:如图19
图19
测试结果如下:图20
图20
这里一共介绍了三种支持跨域的方式:
1. 通过后台模拟Http请求跨域
2. 服务器标记头信息 context.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
3. 通过定义ActionFilter支持跨域其实和第二种原理一样;
4. 通过AspNetCore封装好的Cors来支持跨域;
下期预告
【朝夕Net社区技术专刊】
论ORM框架—EntityFrameworkCore