Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

前端主流跨域方法 #17

Open
amandakelake opened this issue Feb 10, 2018 · 0 comments
Open

前端主流跨域方法 #17

amandakelake opened this issue Feb 10, 2018 · 0 comments
Labels
Javascript Web 网络、性能、优化类

Comments

@amandakelake
Copy link
Owner

amandakelake commented Feb 10, 2018

跨域的本质

跨域是浏览器的限制,服务器之间的请求是没有跨域限制的
所以本地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);
@amandakelake amandakelake added Web 网络、性能、优化类 Javascript labels Feb 10, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Javascript Web 网络、性能、优化类
Projects
None yet
Development

No branches or pull requests

1 participant