跨域问题出现的原因:浏览器安全策略规定只要协议、域名、端口三者有一个不一致就是出现了跨域行为。
1、CORS Cross-Origin Resource Sharing跨域资源共享
定义了在必须访问跨域资源时,浏览器和服务器如何沟通。CORS基本思想就是使用自定义的HTTP头部让浏览器与服务器进行沟通。
CORS关键响应头字段:
Access-Control-Allow-Oringin:必填,表示可以允许请求的来源。设置*表示允许任何源请求。
Access-Control-Allow-Methods:允许的请求方法。
Access-Control-Allow-Credentials:true/false 是否允许发送cookie。默认情况下cookie不包含在CORS请求中。
Access-Control-Allow-Headers:允许携带的首部字段。前段能够通过getResponseheader方法获取的请求头字段。
Access-Control-Max-Age:预检请求有效期。
对于普通跨域请求,服务器设置Access-Control-Allow-Origin将可允许的访问请求来源列为白名单或者设置*表示允许任何源请求。
对于需要携带cookie的跨域请求,前后端都需要设置,前端和服务器都需要设置withCredentials相关字段为true。
2、JSONP
基于script标签没有跨域限制的特性,可以通过动态创建script,然后通过src指定加载其他域资源。
只支持get请求,不支持post等请求。
JSONP由两部分组成: 回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,数据就是传入回调函数中的JSON数据。
如:http://freegeoip.net/json/?callback=handleResponse
3、Nginx反向代理
原理:服务器请求服务器不存在同源策略的限制。(同源策略是浏览器安全策略,与服务器无关。)
客户端请求nginx服务器,在nginx.conf配置文件中配置server监听客户端请求,将location匹配的路径代理到真实的服务器,服务器处理后再将数据响应给nginx再返回给客户端。
4、postMessage
window.postMessage - Web API 接口参考 | MDN
postMessage可以实现页面与其打开的新窗口的数据传递;多窗口之间消息传递;页面与嵌套的iframe消息传递。
//发送消息
window.postMessage(message, targetOrigin, [transfer]);
//在其他窗口或者页面通过监听message事件来获取postMessage传递的数据
window.addEventListener("message", receiveMessage, false);
5、WebScoket
同源协议对WebSocket不适用,因此通过他打开到任何站点的连接。
WebScoket使用自定义协议,其 url模式: ws:// (未加密连接) wss://(加密连接)。使用自定义协议好处是能够在客户端和服务器端发送非常少量的数据,而不必担心http那样字节级的开销。由于传递的数据包很小,因此Webscoket非常适合移动端。
// 创建一个Websocket对象并传入需要连接的url
const socket = new WebSocket("ws://xxxxx");
// 使用send()方法向服务器发送数据
socket.send("xxx");
// 客户端读取服务器发送过来的数据
socket.onmessage = function(event){
var data = event.data;
// 后续数据处理逻辑
}
// 关闭Websocket连接
socket.close();
WebSocket发送和接收到的数据都是字符串,其他数据格式需要进行处理。
WebSocket事件:
open:成功建立连接时触发;
error:发生错误时触发,连接不能持续;
close:连接关闭时触发。
本地开发跨域的解决:
webpack 配置devserver--proxy
// ./webpack.config.js
const path = require('path')
module.exports = {
// ...
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 9000,
proxy: {
'/api': {
target: 'xxx'
}
}
// ...
}
原理:使用http代理中间件 http-proxy-middleware,利用服务器与服务器中间不存在跨域行为的特性实现请求的转发。开发阶段,webpack-dev-server会启动一个本地开发服务器,在浏览器和服务器之间添加一个代理,当本地发送请求时,代理服务器响应该请求并将请求转发到目标服务器,目标服务器响应数据后再将数据返回给代理服务器,最终由代理服务器将数据响应给本地。