JSONP_跨域

2017-11-15  本文已影响0人  cctosuper

题目1: 什么是同源策略

  • 同源策略(Same Origin Policy): 浏览器出于安全方面的考虑, 只允许与本域下的接口交互. 不同源的客户端脚本在没有明确授权的情况下, 不能读写对方的资源.
  • 本域指同域名同协议同端口,即URL完全相同
  • 注意: 对于当前页面来说页面存放的Js文件不重要, 重要的是加载该js页面所在什么域

题目2: 什么是跨域?跨域有几种实现形式

题目3: JSONP 的原理是什么
JSONP就是通过script标签加载数据的方式去获取数据当做JS代码来执行; 提前在页面上声明一个函数, 函数名通过接口传参的方式传给后台, 后台解析到函数名后在原始数据上包裹这个函数名, 发送给前端
题目4: CORS是什么

浏览器将CORS请求分为两类:简单请求和非简单请求
只要同时满足下面两大条件,就属于简单请求

  1. 请求方法是以下三种方法之一:
    HEAD
    GET
    POST
  2. HTTP的头信息不超出以下几种字段:
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
    不能同时满足上面2个条件的,就属于非间请求
    比如对server端有特殊要求的请求,请求方法是PUT或者DELETE、content-type字段类型是application/json的

题目5: 根据视频里的讲解演示三种以上跨域的解决方式 ,写成博客

  1. JSONP
    通常为了减轻web服务器的负载, 我们把js, css, img等静态资源分离到另一台独立域名的服务器上,在HTML页面中再通过相应的标签从不同域名下加载静态资源, 而浏览器允许, 基于此原理, 我们可以通过动态创建script, 再请求一个带参网址实现跨域通信.

    1. 原生实现
    var script = document.creatElement('script');
    script.type = 'text/javascript';
    script.src = 'http://www.domain2.com:8080/login?            user=admin&callback=onBack';
    document.body.appendChild(script);
    function onBack(res){
      alert(JSON.stringify(res));
    }
    服务器返回
    onBack({"status":true, "user":"admin"})
    
    1. jquery ajax:
    $.ajax({
      url:'http://www.domain2.com:8080/login',
      type:'get',
      dataType:'jsonp',// 请求方式为jsonp
      jsonpCallback:"onBack",// 自定义回调函数名
      data:{}
    });
    

后端node.js代码示例:

var querystring = require('querystring');
var http = require('http');
var server = http.createServer();
server.on('request',function(req,res){
varparams = qs.parse(req.url.split('?')[1]);
var fn = params.callback;
// jsonp返回设置
res.writeHead(200,{'Content-Type':'text/javascript'});
res.write(fn+'('+JSON.stringify(params)+')');
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');

jsonp缺点:只能实现get一种请求。
  1. 降域
    此方案仅限主域相同, 子域不同的跨域应用场景.
    实现原理: 两个页面都通过js强制设置document.domain为基础主域, 就实现了同域.
1. 父窗口: (http://www.domain.com/a.html)
document.domain = 'domain.com'
var user = 'admin'
2. 子窗口: (http://child.domain.com/b.html)
document.domain = 'domain.com'
alert('get js data from parent' + window.parent.user)
// 获取父窗口中变量
  1. location.hash + iframe跨域
    实现原理: a域与b域相互通信, 通过中间页c来实现. 三个页面, 不同域之间利用iframe的location.hash传值, 相同域之间直接js访问来通信
    具体实现: a域: a.html > b域: b.html > a域: c.html , ab不同域只能通过hash值单向通信, bc也不同域只能单向通信, 但ac同域, 所以c可通过parent.parent访问a页面所有对象
1. a.html: (http://www.domain1.com/a.html)
var iframe = document.getElementById('iframe')
setTimeout(function(){
  iframe.src = iframe.src + '#user=admin'
}, 1000); // 向b.html传hash值
functionCallback(res){
  alert('data from c.html' + res)
}// 开放给同域c.html的回调方法
2. b.html: (http://www.domain2.com/b.html)
var iframe = document.getElementById('iframe');
window.onhashchange = function(){
  iframe.src += location.hash;
}// 监听a.html传来的hash值,再传给c.html
3. c.html:(http://www.domain1.com/c.html)
window.onhashchange = function(){// 监听b.html传来的hash值
  window.parent.parent.onCallback('hello: ' + location.hash.replace('#user=',''));
}
  1. postMessage
    postMessage是HTML5 XMLHttpRequest Level 2中的API,且是为数不多可以跨域操作的window属性之一,它可用于解决以下方面的问题:
    a.) 页面和其打开的新窗口的数据传递
    b.) 多窗口之间消息传递
    c.) 页面与嵌套的iframe消息传递
    d.) 上面三个场景的跨域数据传递
    用法:postMessage(data,origin)方法接受两个参数
    data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
    origin: 协议+主机+端口号,也可以设置为”*”,表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为”/”。
1. a.html:(http://www.domain1.com/a.html)
var iframe = document.getElementById('iframe');
iframe.onload = function(){
  var data = {name:'aym'};
   iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');
}
window.addEventListener('message', function(e){
  alert('data form domain2 ' + e.data);
}, false);
2. b.html:(http://www.domain2.com/b.html)
window.addEventListener('message', function(e){
  alert('data from domain1 ' + e.data);
  var data = JSON.parse(e.data);
  if(data){
    data.number = 16;
    window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');
  }
}, false);
  1. 跨域资源共享(CORS)
    普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置。
    带cookie请求:前后端都需要设置字段,另外需注意:所带cookie为跨域请求接口所在域的cookie,而非当前页。
    目前,所有浏览器都支持该功能(IE8+:IE8/9需要使用XDomainRequest对象来支持CORS)),CORS也已经成为主流的跨域解决方案。
1. 前端设置:
ajax:
var xhr=newXMLHttpRequest();// IE8/9需用window.XDomainRequest兼容
xhr.withCredentials=true;// 前端设置是否带cookie
xhr.open('post','http://www.domain2.com:8080/login',true);
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xhr.send('user=admin');
xhr.onreadystatechange=function(){
  if(xhr.readyState==4&&xhr.status==200){
    alert(xhr.responseText);
  }
};
2. Nodejs后台示例:
var http=require('http');
var server=http.createServer();
var qs=require('querystring');
server.on('request',function(req,res){
  var postData='';
req.addListener('data',function(chunk){
  postData+=chunk;
});// 数据块接收中
req.addListener('end',function(){
  postData=qs.parse(postData);
// 跨域后台设置
  res.writeHead(200,{
  'Access-Control-Allow-Credentials':'true',// 后端允许发送Cookie
  'Access-Control-Allow-Origin':'http://www.domain1.com',// 允许访问的域(协议+域名+端口)
  'Set-Cookie':'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'// HttpOnly:脚本无法读取cookie
});
res.write(JSON.stringify(postData));
res.end();
});
});
server.listen('8080');
console.log('Server is running at port 8080...');
上一篇 下一篇

猜你喜欢

热点阅读