什么是跨域HTTP请求?

JavaScript出于安全方面的考虑,不允许跨域调用其他页面的对象。比如HTML中a/form/img/css/script/iframe/ajax都可以指向资源,如果发起请求的资源所在域不同于该请求所指向资源所在的域的HTTP请求就叫做跨域HTTP请求。

何为不同的域?

协议+域名+端口号都相同才是同域,有一个不相同都不行。

为什么要有跨域限制?

想一想,如果不做跨域限制,将产生什么问题:

  • iframe嵌入:一个恶意网站的页面通过iframe嵌入了支付宝的登录页面(两者不同域),如果没有任何限制,恶意网页上的javascript脚本就可以在用户登录银行的时候获取用户信息进行恶意操做
  • ajax请求:跨域请求别人的AJAX登录接口,也可以获取到用户信息进行恶意操做

如何对跨域进行限制?

  • 直接不允许跨域请求
  • 服务端可以根据相关的header判断来源,限制访问。但header可以伪造呀~
  • 浏览器发起跨域请求时,进行限制,即同源策略

同源策略
1、限制来自不同源的document或脚本,对当前document读取或设置某些属性
2、禁止ajax直接发起跨域HTTP请求(其实可以发送请求,结果被浏览器拦截,不展示)
3、允许img/css/script(拥有src的标签都有跨域的能力。加载下来就属于当前域了)
4、允许跨域的连接、跳转、表单提交(带来了跨站请求伪造CSRF问题)

怎样实现跨域?

AJAX跨域请求实现方式:

  • 通过代理:自己的服务器实现接口,后台调用其他域的接口
  • JSONP:服务端调用本地js,并将结果带回
  • CORS:扩展HTTP协议,根据服务端返回的有关HEADER来决定是否展示结果

这里主要说一下JSONP和CORS跨域。

JSONP

JSON是一种数据交换格式,而JSONP是一种实现ajax跨域的方式。

原理:
JSONP的原理是利用 <script>标签的src属性加载资源不受同源策略影响,其本质是向服务端请求一段 js 代码,像这样儿:

1
2
3
4
let scriptTag = document.createElement('script')
// 其中cb是回调函数参数的名字,cbname是回调函数的名字,这两个名字要与服务端沟通定义
scriptTag.src = 'http://hcysun.me/xxx?cb=cbname'
document.body.appendChild(scriptTag)

优点:

  • 兼容性好,基本全部兼容

缺陷:

  • 服务端需要指定JS的方法名
  • 只支持GET
  • 确定JSONP请求是否失败并不容易,一般根据超时时间来判断

CORS跨域

CORS(Cross-Origin Resource Sharing)跨域资源共享。它是一个规范,可以简单理解为对HTTP协议进行了扩展,增加了一些http header,让服务器能声明那些来源可以通过浏览器访问该服务器上的资源。

原理:
1、当浏览器发现我们的XHR请求不符合同源策略时,会在请求头添加 Origin 字段,代表请求的来源
2、服务端需要处理请求头部的 Origin 字段,根据情况在响应头中添加

  • Access-Control-Allow-Origin指定一个允许向该服务器提交请求的URI.对于一个不带有credentials的请求,可以指定为*,表示允许来自所有域的请求
  • Access-Control-Allow-Methods在响应预检请求的时候使用.指明资源可以被请求的方式有哪些(一个或者多个)
  • Access-Control-Allow-Headers在响应预检请求的时候使用.用来指明在实际的请求中,可以使用哪些自定义HTTP请求头
    等头信息。

缺陷:
兼容性问题

更多:cors