MLuminary/Blog

跨域问题总结

MLuminary opened this issue · 0 comments

跨域问题总结

跨域问题是日常中必须要面对的,每次面试必考跨域也体现了跨域技术的重要性,跨域的文章也多的数不过来,今天这篇文章主要是用来总结自己每种跨域技术的尝试,如果有幸能帮到别人那就再好不过了

自己用 node 搭了两个服务器,前台设置的端口为 3002,模拟的服务端设置的端口为 3001

跨域问题的出现是由于「同源策略」引起的,「同源」就指的是三个相同,即「协议相同」、「域名相同」、「端口相同」,「同源策略」使得以下三种行为受到限制

  • Cookie、LocalStorage 和 IndexDB 无法获取
  • DOM 无法获取
  • Ajax 请求无法发送

具体情况还请移步浏览器同源政策及其规避方法

自己在这还是稍微总(jie)结(jian)一下,写一遍加深一下印象

对于 Cookie 和 iframe

对于 Cookie 和 iframe ,如果两个网页一级域名相同,只是二级域名不同,比如 a.hutchins.comb.hutchins.com ,浏览器可通过设置相同的 document.domain

document.domain = 'hutchins.com';

服务器也可以在设置 Cookie 的时候,指定 Cookie 的所属域名为一级域名,比如

Set-Cookie: key=value; domain=hutchins.com; path=/

这样的话二级域名和三级域名不做任何设置就可以读取这个 Cookie

window.postMessage

H5 引入了全新的 API :「跨文档通信 API」

otherWindow.postMessage(message, tragetOrigin);
  • otherWindow 窗口
  • message 要发送的信息
  • targetOrigin 指定哪些窗口可以接受到信息,* 表示无限制

接收窗口通过 message 方法接收

window.addEventListener('message' function(e) {

})

message 的事件对象有以下三个属性

  • event.source 发送消息的窗口
  • event.origin 消息发向的网址
  • event.data 发送的消息

AJAX 跨域

jsonp 跨域

jsonp 的原理就是动态创建 script 标签,然后用 scriptsrc 属性引用外部跨域链接,通过回调函数参数接受后台传递的信息

//原生js
var script = document.createElement('script');
script.type = 'text/javascript';

//传参并指定回调函数执行函数为onBack
script.src = 'http://localhost:3001/api/jsonp?uname=hutchins&callback=onBack';
document.body.appendChild(script);

//回调执行函数
function onBack(res) {
  console.log(JSON.stringify(res));
}
//利用jquery ajax
$.ajax({
  url: 'http://localhost:3001/api/jsonp?uname=hutchins',
  type: 'get',
  dataType: 'jsonp', // 请求方式为jsonp
  jsonpCallback: 'onBack', // 自定义回调函数名
  data: {},
  success: function(data) {
    console.log(data);
  }
});
//node 后台处理前端请求的函数
module.exports = {
  //jsonp
  jsonpf: function(req, res) {
    var params = req.query;
    var fn = req.query.callback;

    res.writeHead(200, { 'Content-Type': 'text/javascript' });
    res.write(fn + '(' + JSON.stringify(params) + ')');
    res.end();
  }
};

但是 jsonp 只能支持 Get 请求

跨域资源共享 「CORS」

请求分为「简单请求」和「非简单请求」,而处理这两种请求的方式很不同,这里只说一下「简单请求」

请求方式为以下几种

  • HEAD
  • GET
  • POST

HTTP 的消息头不超出以下几种字段

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type 只限于 application/x-www-form-ulrencoded、multipart/form-data、text/plain
// 原生js
var xhr;
if (window.XMLHttpRequest) {
  xhr = new XMLHttpRequest();
} else {
  xhr = new XDomainRequest(); //兼容 IE8/9
}

//前端设置 cookie
xhr.withCredentials = true;

xhr.open('post', 'http://localhost:3001/api/cors', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('uname=hutchins');

xhr.onreadystatechange = function() {
  if (xhr.readyState == 4 && xhr.status == 200) {
    console.log(xhr.responseText);
  }
};
//跨域后台设置
res.writeHead(200, {
  'Access-Control-Allow-Credentials': 'true', //后端允许发送 cookie
  'Access-Control-Allow-Origin': 'http://localhost:3002'
  // 'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'  // HttpOnly的作用是让js无法读取cookie
});

res.write(JSON.stringify(postData));
res.end();