前端中的同源策略与三种跨域资源共享方法

同源策略

什么是同源

在了解跨域这个概念以前首先要知道的是何为同源策略。所谓的同源是一种安全机制,为了预防某些恶意行为(例如 Cookie 窃取等),浏览器限制了从同一个源加载的文档或脚本如何与来自另外一个源的资源进行交互。而知足同源要具有三方面:协议相同域名相同端口相同javascript

如下是对于http://domain.com/dir/index.html(默认端口 80)来进行同源判断:html

  1. http://domain.com/dir2/info.html(同源)
  2. https://domain.com/dir/index.html(非同源,协议不相同)
  3. http://www.domain.com/dir/index.html(非同源,域名不一样)
  4. http://domain.com:233/dir/index.html(非同源,端口不一样)

什么地方有要求同源

  1. Ajax 通讯
  2. Cookie
  3. LocalStorage
  4. IndexDB
  5. DOM 的操做

跨域资源共享

同源策略对于用户信息安全是必不可少的,可是实现合理的跨域请求也是很重要的,因而 W3C 就定了一个叫CORS(Cross-Origin Resource Sharing)的草案,也就是跨域资源共享。其基本思想就是使用自定义的 HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功或是失败。java

CORS 的简单请求原理

实现 CORS 须要浏览器与服务器的同时支持。例如发送一个简单的GETPOST请求,浏览器会为其添加一个Origin的头,其包含页面的源信息(协议、域名和端口),如:jquery

Origin: http://domain.com
复制代码

若服务器认为该请求可接受,就在Access-Control-Allow-Origin头部中回发相同的源信息(咱们有时调用的公共 API,大部分都是将该头部设为*,可是它们都不发送 Cookie)。要注意的是请求和响应都不包含 Cookie 信息。nginx

以上都为简单请求,对于非简单请求,CORS 经过一种叫作 Preflighted Requests 的透明服务器验证机制支持开发者使用自定义头部信息或者 GET 和 POST 以外的方法,不过代价是在正式通讯前增长一次 HTTP 请求,这里就不详细描述了。ajax

浏览器对 CORS 的实现

现代浏览器都对 CORS 提供了原生支持(IE八、9 是利用XDomainRequest,不过已废弃),无需编写额外代码便可触发简单的跨域行为,由于浏览器会自动帮你添加一些头部信息,可是有如下限制:json

  1. 不可以使用setRequestHeader()设置自定义头部。
  2. 默认状况下不能请求 Cookie 等凭据,除非服务器在响应头中将Access-Control-Allow-Credentials设为true
  3. 调用getAllResponseHeaders()会返回空字符串。

图像 Ping

该跨域技术主要是利用<img>标签设置src属性(请求地址一般都带有查询字符串),而后监听该<img>onloadonerror事件来判断请求是否成功。响应的内容一般是一张 1 像素的图片或者204响应。跨域

图片 Ping 有两个缺点:浏览器

  1. 由于是经过<img>标签实现,因此只支持GET请求。
  2. 没法访问服务器响应脚本,只能用于在浏览器与服务器之间进行单向通行。

因为以上特色,图片 Ping 方法经常使用于跟踪用户点击页面或动态广告的曝光次数。安全

JSONP

JSONP 是 JSON with padding 的简写,其主要是利用动态建立<script>标签向服务器发送 GET 请求,服务器收到请求后将数据放在一个指定名字的回调函数中并传送回来。接下来看一下简单示例: 浏览器

//对建立标签行为进行封装
function addScriptTag(src) {
  var script = document.createElement('script')
  script.setAttribute("type","text/javascript")
  script.src = src
  document.body.appendChild(script)
}

//当浏览器加载完毕时向服务器发送请求
window.onload = function () {
  addScriptTag('http://domain.com/data?callback=getdata')
}

//服务器收到上面的请求后,将数据放在回调函数的参数(data)中返回
function getdata(data) {
  console.log(data)
}
复制代码

jQuery 也有对 JSONP 的封装,有兴趣的能够了解一下(文章尾部连接)

服务器

//服务器获取参数名后,将回调函数和参数拼接为字符串返回
response.send(
  `${query.callback}({ "name": "Hello" })`
)
复制代码

其余的跨域方法

跨域方法其实还有很多,这里先总结这么多,日后若时间容许的话就更新 😬

  • HTML5 的 postMessage
  • WebSocket(固然协议就不同了)
  • document.domain(iframe)
  • location.hash(iframe)
  • window.name
  • nginx 反向代理

相关参考

相关文章
相关标签/搜索