跨域的原理与解决方法

在最近的项目中,遇到这样一个场景:合作方开发H5页面并部署在合作方的服务器上,但页面中嵌入了我方的SDK,SDK会直接调用我方的接口,如下图:

跨域的原理与解决方法

文章插图
 
但是控制台中却会收到如下报错:
Access to XMLHttpRequest at 'http://example1.com/test' from origin 'http://example2.com' 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.这就是跨域的报错 。
跨域是什么跨域,是指浏览器不能执行其它网站的脚本 。它是由浏览器的同源策略造成的,是浏览器对JAVAscript实施的安全限制 。
简单来讲,就是从地址A加载的页面,不能访问地址B的服务(如上图) 。此时地址A与地址B不同源 。
所谓同源,就是域名、协议、端口均相同 。举个例子:
http://www.123.com/index.html 调用 http://www.123.com/abc.do (非跨域)http://www.123.com/index.html 调用 http://www.456.com/abc.do (主域名不同:123/456,跨域)http://abc.123.com/index.html 调用 http://def.123.com/server.do (子域名不同:abc/def,跨域)http://www.123.com:8080/index.html 调用 http://www.123.com:8081/server.do(端口不同:8080/8081,跨域)http://www.123.com/index.html 调用 https://www.123.com/server.do (协议不同:http/https,跨域)如上所述,由于合作方的域名与我方的域名不同,从合作方加载的页面,调用我方接口的时候,就会出现跨域的报错 。
是否有办法可以解决这个问题呢,需要从CORS说起 。
CORS随着互联网的发展,同源策略严重影响了项目之间的连接,尤其是大项目,需要多个域名配合完成,因此W3C推出了CORS,即Cross-origin resource sharing(跨来源资源共享) 。CORS的基本思想就是使用额外的HTTP头部让浏览器与服务器进行沟通,从而决定是否接受跨域请求 。
CORS需要浏览器和服务器同时支持,目前,所有浏览器都支持该功能 。对于开发者来说,CORS通信与同源的AJAX通信没有区别,代码完全一样 。浏览器在跨域访问时,会自动添加HTTP头信息,或者发起预检请求,用户对此毫无感知 。因此是否支持跨域请求,关键在于服务器是否做了CORS配置,允许跨域访问 。
浏览器将跨域请求分为两类:简单请求和非简单请求 。
同时满足以下两大条件的,就属于简单请求:
  • 请求方法是以下3种之一:GETPOSTHEAD
  • HTTP头信息不超出以下字段:AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type:仅限于三个值Application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不满足以上条件的,就属于非简单请求 。如我们常用的json格式请求,由于其Content-Type的值为application/json,因此属于非简单请求 。
对于这两种请求,浏览器的处理方式是不一样的 。
简单请求对于简单请求,浏览器采用先请求后判断的方式,即浏览器直接发出CORS请求,即在请求头中增加Origin字段,如图:
跨域的原理与解决方法

文章插图
 
Origin字段用来向服务器说明,本次请求来自于哪个源(协议+域名+端口),服务器决定是否允许这个源的访问 。
服务器判断该源如果不在自己允许的范围内,就返回一个正常的HTTP响应 。浏览器判断响应头中是否包含Access-Control-Allow-Origin字段,如果没有,浏览器就知道服务器是不允许跨域访问的,就会抛出错误 。
如果Origin在服务器允许的范围内,服务器的HTTP响应中,就会包含如下字段:
跨域的原理与解决方法

文章插图
 
Access-Control-Allow-Origin 它的值要么是请求时Origin字段的值,要么是一个*(表示接受任意域名的请求) 。 Access-Control-Allow-Credentials 它的值是一个布尔值,表示是否允许发送Cookie 。默认情况下,Cookie不包括在CORS请求之中 。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器 。 Access-Control-Allow-Headers 允许浏览器在CORS中发送的头信息 。 Access-Control-Allow-Methods
允许浏览器在CORS中使用的方法 。
浏览器收到服务器返回的HTTP响应后,即可知道什么样的CORS请求是被允许的 。
非简单请求对于非简单请求,浏览器采用预检请求,询问服务器是否支持跨域请求 。在正式的请求之前,浏览器会预先发送一个额外的OPTIONS请求,询问服务器当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP方法和头字段 。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错 。如图:


推荐阅读