在前后端通信时,有时会遇到跨域问题,接下来将从以下几个方面进行跨域详解。
1. 为什么会有跨域问题?
2. 什么是同源策略?
3.前后端通信方式有哪些?
4.解决跨域通信的方式有哪些?
5.解决跨域方式详细说明
为什么会有跨域问题?
答:是由于浏览器的同源策略。
什么是同源策略?
答:同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能。 同源策略限制了从一个源加载的文件或脚本如何与另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的安全机制。
那什么是源呢?源就是由:协议 + 域名 + 端口号 组成;
只有同源的时候才可以完成通信;如果是非同源的话,浏览器会在控制台中报一个异常,提示拒绝访问。
同源策略的限制:
1、cookie,localstorage和IndexDB无法读取;
2、DOM无法获取;
3、Ajax请求不能发送
前后端通信方式有哪些?
答:ajax; webSocket; CORS(跨域资源共享)
解决跨域通信的方式有哪些?
答:jsonp; webSocket; CORS; Hash; postMessage;
解决跨域方式详细说明
1--jsonp
原理:利用<script>元素的开放策略,可以加载其他源的文件和动态产生的json,但是JSONP请求一定要对方的服务器支持才可以使用。
具体写法:
第一种跟第三种写法的原理是一样的,都是利用script标签,创建回调函数fn,把那个跨域的api接口地址赋给script的src,并把新建的函数作为参数传递给接口(?callback=fn),后端接受请求后,会把传进来的函数名fn和查询到的数据组合(fn({data:“张三”}))后返回;
第二种写法是利用jQuery的jsonp请求,在ajax请求时指定服务器返回的数据类型,但是jsonp只支持get请求,不支持post;
<!-- 客户端 --> <script> function call(data){ alert(data) } // 第一种:动态添加script标签 function createScript(src){ var script = document.createElement("script"); script.setAttribute("type","text/javascript"); script.src = src; document.body.appendChild(script); } createScript("http://127.0.0.1:3000/?callback=call"); // 第二种:jquery的jsonp方式 $.ajsx({ url: "http://127.0.0.1:3000/", type: "GET", //jsonp只支持get请求,不支持post dataType: "jsonp", //指定服务器返回的类型 success: function(data){ console.log(JSON.stringify(data)); } }) </script> <!-- 第三种:直接使用script标签 --> <script type="text/javascript" src="http://127.0.0.1:3000?callback=call"></script>
<!-- 服务端 -->
app.get('/',function(req,res){
var callback = req.query.callback;
var data = {nama:"Marry"};
res.send(callback+"("+data+")");
res.end();
});
2--webSocket
WebSocket 简介:
是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket使得客户端和服务器端的通信更加方便,允许服务端主动向客户端返回数据,使用WebSocket,客户端和服务器端只需建立一次“握手”,就可以建立永久连接,并进行双向数据请求。
WebSocket的写法:
// 浏览器发出的WebSocket请求的头信息。 GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket //Upgrade 字段必须设置 Websocket,表示希望升级到 Websocket 协议。 Connection: Upgrade //Connection 必须设置 Upgrade,表示客户端希望连接升级。 Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw== Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13 //表示支持的 Websocket 版本 Origin: http://example.com //表示在浏览器中发起此 Websocket 连接所在的页面
浏览器请求头中有“Origin”,表示发起连接的源,正是由于有这个字段,才可以进行非同源通信,服务器接收到请求后,会根据这个字段判断是否允许通信,如果该地址在允许的通信的名单中,则服务器会返回以下信息。
// 服务器回应 HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s= Sec-WebSocket-Location: ws://example.com/
3--CORS
CORS简介:
CORS全称是“跨域资源共享”,它允许浏览器向不同源(协议+域名+端口号)的服务器发送XMLHttpRequest请求,从而解决了ajax只能同源访问的限制。
CORS需要客户端和服务器都配置才可以正常使用,CORS的通信与Ajax通信对于开发者来说代码都是一样的,只是当浏览器识别到是Ajax请求时,会自动给请求的头信息里增加一些信息,但用户是发觉不到的。
因此,实现CORS通信的关键是服务器端的接口要支持CORS,只要实现了CORS接口,就可以进行跨域通信了。
CORS写法:
// 服务器端设置 var express = require('express'); var app = express(); var allowCrossDomain = function (req, res, next) { res.header('Access-Control-Allow-Origin', 'http://localhost:3001'); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE'); res.header('Access-Control-Allow-Headers', 'Content-Type'); next(); } app.use(allowCrossDomain);
CORS参数介绍:
Access-Control-Allow-Methods:该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。
Access-Control-Allow-Origin:该字段必填。它的值要么是请求时Origin字段的具体值,要么是一个*,表示接受任意域名的请求。
Access-Control-Expose-Headers:该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。
注意事项:
使用cors时需要传递cookie,虽然可以跨域通信,但cookie依然遵循同源策略,只有用服务器设置的cookie才可以获取到并上传,其他域名的不可以。
4--Hash
Hash写法:
// 当前页面A通过iframe或者frame嵌入了页面B,通过hash实现A、B页面通信 //A中代码 var B = document.getElementsByTagName('iframe'); var data = JSON.stringify({name:"zhangsan"}) B.src = B.src + data;//data是要传递的参数,已转换成字符串 //B中代码 window.onhashchange = function(){//通过onhashchange监听hash的变化 var dataVal = window.location.hash; }
Hash主要是利用onhashchange 这个事件监听hash的变化,来获取传递的参数。
5--postMessage
postMessage简介:
在HTML5中新增了postMessage方法,postMessage可以实现跨文档消息传输(Cross Document Messaging),Internet Explorer 8, Firefox 3, Opera 9, Chrome 3和 Safari 4都支持postMessage。
//窗口A(http://a.com)向跨域的窗口B(http://b.com)通信 //A中代码 a.postMessage("data","http://b.com");//第一个参数为要传递的数据;第二个参数是要通信的源。 //B中代码 b.addEventListener("message", function(event){ console.log(event.origin,event.source,event.data)//可以获取到发送消息的源,发送消息的窗口对象,还有传递的数据
})
postMessage主要是用postMessage方法和message事件相结合完成跨域通信的。
以上就是同源策略和跨域通信的相关解释,有不对的地方,欢迎大家指正!
-THE END-