跨域以及解决方案
理解跨域
不同源地址之间的请求称之为跨域请求(跨源)
所谓同源就是同域名、同协议、同端口,只有同源的地址才可以相互通过ajax方式请求
btn.onclick = function(){ let xhr = new XMLHttpRequest; // xhr.open('get','http://localhost:2019');//非跨域 xhr.open('get','http://www.baidu.com');//跨域 xhr.onload = function(){ document.write(xhr.responseText) } xhr.send(); }
控制台出现 Access-Control-Allow-Origin,就说明已经跨域了
是什么导致了跨域的产生,就会说到浏览器的一种安全机制 —— 同源策略
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响
同源策略是一种安全协议,指一段脚本只能读取来自同一来源的窗口和文档的属性
同源策略限制以下几种行为:
1.) Cookie、LocalStorage 和 IndexDB 无法读取
2.) DOM 和 Js对象无法获得
3.) AJAX 请求不能发送
解决跨域的方案:
1、CORS
CORS是一个W3C标准,全称是"跨域资源共享"
浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉
因此实现CORS通信的关键是服务器,只要服务器实现了CORS接口,就可以跨源通信
高版本的XMLHttpRequest + 服务器权限解决跨域问题
// 处理成功失败返回格式的工具 const {successBody} = require('../utli') class CrossDomain { static async cors (ctx) { const query = ctx.request.query // *时cookie不会在http请求中带上 ctx.set('Access-Control-Allow-Origin', '*') ctx.cookies.set('tokenId', '2') ctx.body = successBody({msg: query.msg}, 'success') } } module.exports = CrossDomain
前台只需要正常发送请求
fetch(`http://localhost:9871/api/cors?msg=helloCors`).then(res => { console.log(res) })
2、JSONP(json+padding)
script标签中的src能够直接跨域访问资源,并且尽量解析js代码
jsonp必须具备以下条件:
1)保证全局有个函数
2)数据必须是这个函数的调用格式
3)当要请求数据时候,创建一个script标签,把scr等于请求的接口,再把script标签插入到页面,这个时候就做到了按需请求
function fn(data){ let html = ''; data.s.forEach(e=>{ html += `<li>${e}</li>` }) box.innerHTML = html; console.log(data) } txt.onkeyup = function(){ let jk = document.createElement('script'); jk.src="https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd="+this.value+'&cb=fn' document.getElementsByTagName('head')[0].appendChild(jk); }
jquery的jsonp
txt.onkeyup = function(){ $.ajax({ url:'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?cb=?', data:{ wd:$(this).val() }, dataType:'jsonp', success(data){ let html = ''; data.s.forEach(e=>{ html += `<li>${e}</li>`; }); ul.innerHTML = html; } }); }
3、服务器代理
通过服务器的文件能访问第三方资源,这个服务器文件又和当前请求的页面同源
这个时候,当前请求的页面去访问服务器文件,就等同于直接请求第三方资源
4、WebSocket协议跨域
WebSocket protocol是HTML5一种新的协议。它实现了浏览器与服务器全双工通信
同时允许跨域通讯,是server push技术的一种很好的实现
前台代码
<div>user input:<input type="text"></div> <script src="./socket.io.js"></script> <script> var socket = io('http://www.domain2.com:8080'); // 连接成功处理 socket.on('connect', function() { // 监听服务端消息 socket.on('message', function(msg) { console.log('data from server: ---> ' + msg); }); // 监听服务端关闭 socket.on('disconnect', function() { console.log('Server socket has closed.'); }); }); document.getElementsByTagName('input')[0].onblur = function() { socket.send(this.value); }; </script>
后台代码
var http = require('http'); var socket = require('socket.io'); // 启http服务 var server = http.createServer(function(req, res) { res.writeHead(200, { 'Content-type': 'text/html' }); res.end(); }); server.listen('8080'); console.log('Server is running at port 8080...'); // 监听socket连接 socket.listen(server).on('connection', function(client) { // 接收信息 client.on('message', function(msg) { client.send('hello:' + msg); console.log('data from client: ---> ' + msg); }); // 断开处理 client.on('disconnect', function() { console.log('Client socket has closed.'); }); });