首先,何为同源策略? 同源策略
是由Netspace提出来的一种安全策略。同源
的源
由一个URL的协议、主机、端口定义,若是这三者一致,那么就是同源。javascript
当不一样源的时候,哪些操做被容许呢?html
<script>
加载Javascript<link>
加载CSS<img>
加载图片<video><audio>
加载多媒体<object><embed><applet>
加载插件<iframe>
加载任何东西哪些不容许呢?前端
XMLHttpRequest
不被容许一个页面的源能够修改的,经过document.domain
,好比一个页面a.b.com
嵌入iframec.b.com
,这时候只须要把两个页面的document.domain
设置为b.com
便可。java
跨域是针对前端来的,服务端是没有跨域这个东西的,因此后台设置一下,前端访问时访问一个同源页面,而后后台把请求的数据转到不一样源的页面便可。node
前端web
var xhr = new XMLHttpRequest();
var url = 'http://localhost:3000/api'; // 向http://localhost:3000/api发出请求,获取数据
xhr.open('GET', url);
xhr.send(null);
xhr.onreadystatechange = () => {
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { // 若是请求成功
text.innerHTML = xhr.response;
}
}
复制代码
同域服务器ajax
// nodeJs express
var proxy = require('http-proxy-middleware');
var app = express();
app.use('/api', proxy({target: 'http://localhost:3001/', changeOrigin: true}));
复制代码
由于<script>
内嵌资源是容许的,因此能够把请求的接口放在<script>
标签上,而后附带咱们的回调函数express
前端json
<script src="http://other.com/ajax.json?callback=myFunction"></script>
复制代码
跨域服务器api
接口获取到callback后,把返回的数据做为参数传给callback并执行。
// nodeJs express
app.get('/', function (req, res) {
var callbackName = req.query.callback;
res.send(callbackName+"({'message': 'hello world'});");
})
复制代码
缺点
这个是HTML5的一个接口,用到了接口里面的postMessage
方法,主要用于两个窗口之间交换数据,不能用于与服务器交换数据。
otherWindow.postMessage(message, targetOrigin, [transfer]);
复制代码
otherWindow
是接收方窗口的引用。通常是如下几种方式:
而message
是支持几乎全部形式的数据,transfer
可省略
用法:
// 父页面
document.getElementByTagName('iframe')[0].contentWindow.postMessage({"age":10},'http://localhost:8080');
// 监听有没有数据返回来
window.addEventListener('message',function(e){
console.log(e)
});
复制代码
// iframe
window.addEventListener('mesage',function(e){
if(e.origin !== 'http://localhost:8081'){
return;
}
console.log(e);
e.souce.postMessage('hello world',e.origin)
})
复制代码
CORS须要浏览器和服务器同时支持,关键是服务器,只要服务器实现了CORS接口就能够跨域通讯。
CORS将请求分为两类:简单请求和非简单请求。
非简单请求的条件:
Content-type
字段是application/json
对于简单请求,浏览器在头信息里面加一个origin
字段,说明本次请求来自哪一个源(协议+主机+端口),服务器根据这个值,决定是否赞成。若是origin
不在指定的源里面,就会返回一个正常的HTTP回应,可是里面不包含Access-Control-Allow-Origin
就知道出错了,从而抛出一个错误,被XMLHttpRequest
的onerror
回调函数捕获。
这种错误没法经过状态码判断,有多是
200
若是源在许可范围内,就会返回响应,并多出几个信息字段。
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
复制代码
Access-Control-Allow-Origin
必须字段。若是是*
,表示接收任何域名的请求。Access-Control-Allow-Credentials
可选字段。CORS请求默认是不带cookie和HTTP信息的,若是为true
,代表服务器许可请求中能够包含cookie 。除了服务器容许请求附带cookie和HTTP信息,客户端也必须容许var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
复制代码
Access-Control-Expose-Headers: FooBar
该字段可选。CORS请求时,XMLHttpRequest
对象的getResponseHeader()
方法只能拿到6个基本字段:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma
。若是想拿到其余字段,就必须在Access-Control-Expose-Headers
里面指定。上面的例子指定,getResponseHeader('FooBar')
能够返回FooBar字段的值。前端
var xhr = new XMLHttpRequest();
var url = 'http://localhost:3001'; // 请求的3001端口获取数据
xhr.open('GET', url); // 与3001端口创建一个链接
xhr.send(null); // 发送给3001端口数据为空
xhr.onreadystatechange = () => { // 请求状态改变后调用这个函数
if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) { // 若是请求成功
text.innerHTML = xhr.response;
}
}
复制代码
跨域服务器
// nodeJs express
var app = express();
app.get('/', (req, res) => {
res.set('Access-Control-Allow-Origin', 'http://localhost:3000'); // 设置容许跨域的origin,容许3000端口访问本端口(3001)
res.send("Hello world");
});
复制代码
非简单请求的不一样之处在于在正式通讯以前会有一次HTTP查询请求,成为「预检」请求(preflight)
前端
var url = 'http://localhost:3001';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();
复制代码
浏览器
浏览器发现这是一个非简单请求,就会自动发出一个预检请求。
OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
复制代码
预检的请求方式是OPTIONS
,表示这个请求是用来询问的。
跨域服务器
服务器收到预检请求后,检查了Origin
、Access-Control-Request-Method
和Access-Control-Request-Headers
字段之后确认容许跨域请求,而后作出回应
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
复制代码
Access-Control-Allow-Methods
代表服务器支持的全部跨域请求的方法。
若是预检请求经过,之后每次的CORS请求就跟简单请求同样了。
缺点
非简单请求,第一次请求会发送两次请求
WebSocket是不受同源限制的,因此跨域什么的就不存在了。
基本用法:
var ws = new WebSocket("wss://echo.websocket.org");
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
};
复制代码