同源政策和跨域

同源政策

同源政策(same-origin policy),作为浏览器安全的基石,可以保证用户信息的安全,防止恶意的网站窃取数据,

1.何为同源

  • 协议相同
  • 域名相同
  • 端口相同

2.非同源受限制的行为

  • 无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
  • 无法接触非同源网页的 DOM
  • 无法向非同源地址发送 AJAX 请求(可以发送,但浏览器会拒绝接受响应)

注意: 对于当前页面来说页面存放的 JS 文件的域不重要,重要的是加载该 JS 页面所在什么域

跨域

当浏览器在一个页面上去请求另一个域名的资源,这两个域是不同源的,就需要跨域的操作;

跨域的方式:JSONP、CORS、降域 和 postMessage

1.JSONP(JSON with padding)

通过JSONP实现跨域的基本思想是:HTML中的<script>标签可以下载其它域下的js文件,这种做法是不受同源政策的限制的。因此,可以利用这个特性从不同源的域下获取数据。下面通过一个例子讲解实现方式。

  • HTML的内容
<body>
  <ul></ul>
  <button>展示数据</button>
</body>
<script>
function $(selector) {
  return document.querySelector(selector)
}

//这里给button绑定事件,点击button时,在<head>里添加一个<script>标签,指定src
$('button').onclick = function(){
  var script = document.createElement('script')
  script.src = 'http://127.0.0.1:8080/getData?callback=showData';
  document.head.appendChild(script)
}

//这里声明showData函数
function showData(data) {
  var html = ''
  for(var i=0; i<data.length;i++) {
    html += '<li>' + data[i] + '</li>'
  }
  $('ul').innerHTML = html
}
</script>
  • 搭建一个服务器
var http = require('http')
var fs = require('fs')
var path = require('path')
var url = require('url')

var server = http.createServer(function(req,res) {
  routePath(req,res)
})

function routePath(req,res) {
  var pathObj = url.parse(req.url,true)
  switch(pathObj.pathname) {
    case '/getData':
    var data = [
      '数据1',
      '数据2',
      '数据3'
    ]

//<script>标签加载的是JS文件,服务器返回的数据是JSON格式的数据,所以这里对返回的数据做处理
    if(pathObj.query.callback) {
      res.end(pathObj.query.callback + '(' + JSON.stringify(data) + ')')
//最终得到的是执行showData函数,参数是原本要返回的数据,即上面的data
    }else{
      res.end(JSON.stringify(data))
    }

    break;

//这里是没有路由时,处理静态目录
    default:
      fs.readFile(path.join(__dirname, pathObj.pathname), function(e, data){
        if(e){
          res.writeHead(404, 'not found')
          res.end('<h1>404 Not Found</h1>')
        }else{
          res.end(data)
        }
      }) 
  }
}

server.listen(8080)

我们打开html的url是http://localhost:8080/index.html,而我们在html中添加的<script>的标签的src是http://127.0.0.1:8080/getData?callback=showData,根据同源政策,这两个是不同源的。但是,<script>标签加载数据是不受同源政策限制的。

正常的用ajax发送请求
//对js做个修改
$('button').onclick = function(){
var xhr = new XMLHttpRequest()
xhr.open('GET','http://127.0.0.1:8080/getData?callback=showData')
xhr.onload = function(){
 console.log(xhr.responseText)
 }
 xhr.send()
}

点击按钮,发送请求后,查看控制台,发现浏览器拒绝接受响应,因为发送请求的url和当前页面的url是不同源的

2.CORS

CORS,全称是“跨域资源共享”(Cross-origin resource sharing),它允许浏览器向跨域的服务器,发出XMLHttpRequest请求,从而克服了 AJAX 只能同源使用的限制。

基本原理是:当使用 XMLHttpRequest 发送请求时,浏览器如果发现该请求不符合同源政策,会给该请求加一个请求头:Origin,服务器进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin; 浏览器接收响应时,判断响应头中是否包含 Origin 的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。

一个例子:

  • HTML的内容
<body>
  <ul></ul>
  <button>展示数据</button>
</body>
<script>
  function $(selector) {
    return document.querySelector(selector)
  }

  function showData(data) {
    var html = ''
    for(var i=0; i<data.length;i++) {
      html += '<li>' + data[i] + '</li>'
    }
    $('ul').innerHTML = html
  }

  $('button').onclick = function(){
    var xhr = new XMLHttpRequest()
    xhr.open('GET','http://127.0.0.1:8080/getData')
    xhr.onload = function(){
      showData(JSON.parse(xhr.responseText))
    }
    xhr.send()
  }
</script>
  • 搭建服务器
var http = require('http')
var fs = require('fs')
var path = require('path')
var url = require('url')

var server = http.createServer(function(req,res) {
  routePath(req,res)
})

function routePath(req,res) {
  var pathObj = url.parse(req.url,true)
  switch(pathObj.pathname) {
    case '/getData':
      var data = [
        '数据1',
        '数据2',
        '数据3'
      ]
//这里是关键的一步,给响应头添加Access-Control-Allow-Origin,后面的值表示接受该域名的请求
      res.setHeader('Access-Control-Allow-Origin','http://localhost:8080')
      res.end(JSON.stringify(data))

    break;

    default:
      fs.readFile(path.join(__dirname, pathObj.pathname), function(e, data){
        if(e){
          res.writeHead(404, 'not found')
          res.end('<h1>404 Not Found</h1>')
        }else{
          res.end(data)
        }
      }) 
  }
}

server.listen(8080)

我们点击按钮,发送请求,同时查看请求头和响应头的内容。

请求头
响应头

我们可以看到,Origin的值和Access-Control-Allow-Origin的值一样,最终的请求也是有效的,浏览器页接受了响应。

与JSONP的比较

CORS 与 JSONP 的使用目的相同,但是比 JSONP 更强大。JSONP 只支持GET请求,CORS 支持所有类型的 HTTP 请求。JSONP 的优势在于支持老式浏览器,以及可以向不支持 CORS 的网站请求数据。

3.降域

降域是通过设置 document.domain 的值,解决跨域问题;
降域的适用范围较窄,一般是页面中有iframe元素,需要获取iframe中的页面的数据时使用降域来解决跨域的问题;

基本原理:例如
A页面域名为:a.com;ifram中引入B页面
B页面域名为:b.com;
在A、B页面写入document.domain = 'localhost:8080.com';(这里的值是主域名)
这样的话就可以在A页面中获取B页面的DOM数据,操作B页面中的元素;

4.postMessage(不常用)

这个方法是利用HTML5中引入的一个API:window.postMessage() ;
它的原理就是,比如一个父窗口,向一个子窗口(比如ifram)发送消息,子窗口可以通过message事件,监听到父窗口发送过来的消息,并作出相应的操作,同理,子窗口也能向父窗口发送消息。通过这种操作也能实现跨域。

参考

降域和postMessage
JavaScript教程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343