前端主流跨域方法
amandakelake opened this issue · 0 comments
跨域的本质
跨域是浏览器的限制,服务器之间的请求是没有跨域限制的
所以本地node起的服务器或者nginx服务器有两个作用
1、充当静态文件服务器,可以查看本地页面,以及监测文件改动
2、充当代理服务器,比如node的proxyTable用的是http-proxy-middleware中间件,原理是浏览器发给自己的服务端,然后由自己的服务端再转发给要跨域的服务端,做一层代理
在浏览器端跨域,可能导致获取到其他网站的敏感信息或者越权操作,比如拿到银行的登录状态或者执行转账操作,所以应当禁止。
服务端跨域没有这个问题,因为用户的这些状态信息都是在浏览器端保存的,服务器只能有自己网站的状态信息
到目前为止,常见的跨域方法有以下几种
- CORS
- postMessage
- 各种插件:比如http-proxy-middleware
- Websocket
还有这些老生常谈的,但不经常用的,就忽略而过吧
- document.domain
- location.hash
- window.name
- JSONP
CORS 跨域资源共享
只需要后端同学支持就ok,前端不需要做很多额外工作(除了携带cookie)。
只要服务器返回的相应中包含头部信息Access-Control-Allow-Origin: domain-name
,domain-name为允许跨域的域名,也可以设置成*,浏览器就会允许本次跨域请求
后端允许CROS跨域,前端设置代理链接和允许带上cookie
后端header设置
Access-Control-Allow-Origin
不可以为 *
,因为 *
会和 Access-Control-Allow-Credentials:true
冲突,需配置指定的地址
access-control-allow-credentials: true
access-control-allow-origin: http://localhost:9123
前端设置,以vue+axios举个例子
// 此处是允许带上cookie
axios.defaults.withCredentials = true;
代理的话,现在前后端分离的潮流,都是node服务器起的代理proxyTable
proxy: {
"/fd": {
target:
process.env.NODE_ENV === "production"
? "http://m.domian1.com"
: "http://test.domain.com",
ws: true,
changeOrigin: true,
pathRewrite: {
"/fd": "/"
}
}
},
postMessage
otherWindow.postMessage(message, targetOrigin, [transfer]);
MDN-postMessage
- otherWindow: 其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames
- message:消息内容
- targetOrigin: 接受消息窗口的源,即”协议 + 域名 + 端口”
- transfer:是一串和message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
发送者和接收者都可以通过message事件,监听对方的消息
message事件的事件对象event包含三个属性
- event.source: 发送消息的窗口对象的引用,可以用此在两个窗口建立双向通信。
- event.origin: 发送消息的URI
- event.data: 消息内容
发送方 http://domain-a.com/a.html
<script>
var newWindow = window.open('http://domain-b.com/b.html');
/* 向b.html发送消息 */
newWindow.postMessage('Hello', 'http://domain-b.com/b.html');
/* 双向通信,接收b.html的回复消息 */
var onmessage = function (event) {
var data = event.data;
var origin = event.origin;
var source = event.source;
if (origin == 'http://domain-b.com/b.html') {
console.log(data); //Nice to see you!
}
};
window.addEventListener('message', onmessage, false);
</scirpt>
接收方 http://domain-b.com/b.html
<script>
var onmessage = function (event) {
var data = event.data;
var origin = event.origin;
var source = event.source;
if (origin == 'http://domain-a.com/a.html') {
console.log(data); //Hello
/* 回复a.html的消息 */
source.postMessage('Nice to see you!', 'http://domain-a.com/a.html');
}
};
window.addEventListener('message', onmessage, false);
</script>
WebSocket
/* websocket协议为ws/wss, 类似http/https的区别 */
wsUrl = 'wss://127.0.0.1:8090/ws/';
/* 发送 */
ws = new WebSocket(wsUrl);
/* 连接成功建立时调用 */
ws.onopen = function (event) {
console.log("websocket command onopen");
var msg = {
username: 'YeaseonZhang'
}
/* 通过 send() 方法向服务端发送消息,参数必须为字符串 */
ws.send(JSON.stringify(msg));
};
/* 服务端向客户端发送消息时调用 */
ws.onmessage = function (event) {
/* event.data包含了服务端发送过来的消息 */
console.log("websocket command onmessage: " + event.data);
if (event.data === 'success') {
/* 通过 close() 方法断开websocket连接 */
ws.close();
}
};
/* 连接被关闭时调用 */
ws.onclose = function (event) {
console.log("websocket command onclose: " + event.data);
};
/* 出现错误时调用 */
ws.onerror = function (event) {
console.log("websocket command onerror: " + event.data);
};
插件:比如http-proxy-middleware
其实就是我们日常前后端分离中,node起的最多服务器设置,但一些脚手架,比如vue cli ,create-react-app都帮我们配置好了
var express = require('express');
var proxy = require('http-proxy-middleware');
var app = express();
app.use('/api', proxy({target: 'http://www.example.org', changeOrigin: true}));
app.listen(3000);