浏览器跨域访问到底是怎么回事

从何说起

Access to XMLHttpRequest at 'http://127.0.0.1:3000/' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

  如果你在控制台中看到类似以上的输出信息,这就是跨域访问的拦截提示;那到底什么叫跨域呢?简单一点说,你网页是xxx.com/xxx.html,这个网页中的元素不允许访问除这个域名以外的其他域名下的资源(也许不严谨,化繁为简能快速理解其本质)。再具体一点就是这个页面下的Ajax请求,不能去调类似http://abc.com/xxxx这样的接口,必须是xxx.com下的接口。

出浅入深

  • 什么是域?简单一点,就是域名,http://www.abc.com下的网页只能调http://www.abc.com/开头的接口,否则就是跨域了,跨域就会报错,上面那个错误提示;
  • 为什么不允许跨域?为了安全!废话,到底哪里有风险?简单描述一下, 我们的浏览器可以同时打开多个网站,也就是说浏览器是一个公共场所。不同的站点请求下来的数据可能会被互相“看到”,就像公共澡堂,大家坦诚相见,难免会有非份之想。所以要“隔开”,每个站点下的Ajax只能请求自己站点下的数据,不能请求其他站点的数据,即不允许跨域访问。
  • 到了这里或许你已经有了一点点概念了,原来跨域访问的限制就A站点下的脚本只能从A拿数据,B站点下的脚本只能从B拿数据。如果我A站点确实想拿B站点的数据怎么办,有没有办法呢?肯定是有的,你在B站点上做相关设置,允许别人拿咯。
  • 误区来了,由于在服务器上做相关匹配就可以允许跨域,所以很多同学认为只所以不能跨域访问,是服务器做了相关限制?!这是不对的。请注意:跨域访问限制是浏览器的行为。 阻止你跨域进行Ajax请求的是浏览器,不是服务端,并且事实上服务端已经返回了数据到本地,被浏览器拦截下来了,没有呈现到页面上来还抛出了异常。
  • 还有一点疑惑,如果跨域限制是浏览器行为,为什么是在服务器上做相关配置?我们可以理解为“服务器授权”,默认情况下浏览器是不允许跨域的,这样可以为各站点数据增加一点安全保护,但如果你的站点在响应请求的时候,带回信息告诉浏览器:“没事,你尽管让他们都来请求好了,我有什么给什么。”,这样一来跨域的限制就解除了。
  • 再多说两句,为什么App调接口没有跨域的问题?因为跨域的限制是浏览器行为,服务器本身并没有限制访问的源是谁。

简单总结

  跨域访问限制是浏览器为了数据安全而设计的一种保护机制,跨域指的是不两只域名(简单一点就这么认为吧,不要纠结)下的站点数据不能互相访问,换句话说页面中的Ajax请求只能当前站点下的接口,否则就会被抛出异常。

  值得注意的是,这种禁止跨域访问的行为是浏览器的“规矩”,服务端本身没并有这种限制。但可以在服务端做相关配置来允许跨域访问,这是服务端在“授权”,让浏览器解除跨域访问本站的限制。

扩展与思考

  前面一直提到的是Ajax请求,是不是跨域针对的就是Ajax?我的理解是从该页面发出的所有网络请求都在其限制范围内。然而浏览器又并没有对所有的网络请求都做了跨域的限制。

  什么意思呢,比如说img标签中的src属性,当前页面引入一张其他站点的图片资源,这其实是跨域的,可这个是却是合法的,类似的现象还有css资源外链与javascript资源。换句话说,我可以通过script标签的src属性从别的域中拿到数据,浏览器没拦截,然后再想办法将数据取出来不就可以了吗?想得挺美,事实上还真可以。jsonp就是依据这个原理实现的,相关细节不在这里讨论,点到为止。

发表评论