sockjs-client和stompjs

2,598 阅读3分钟
  • SockJS的url是http、https协议,而不是 ws
    • 提供Websocket兼容性实现方法
  • new WebSocket(url) url必须是以ws://或者wss://开始的一个完全限定URL。
const socket = new SockJS("http://127.0.0.1:9091/sbjm-cheng/endpointOyzc"); 
Stomp.over(socket)

const ws = new Websocket("ws://localhost:61614/ws")
Stomp.over(ws)

摘自: 前端vue使用stomp.js、sock.js完成websocket - shine_lovely - 博客园 (cnblogs.com)


  • WebSocket协议定义了两种URL方案(URL Scheme):

    • ws(WebSocket):客户端与服务器之间的非加密流量,与HTTP URI方案类似
    • wss(WebSocket Secure):客户端与服务器之间的加密流量,该方案表示使用传输层安全性(TLS,也叫SSL)的WebSocket连接,使用HTTPS采用的安全机制来保证HTTP连接安全
  • 除了文本,WebSocket消息还可以处理二进制数据,这种数据作为Blob消息或ArrayBuffer消息。

  • WebSocket 发送文本/二进制消息

ws.close(1000, "Closing normally");
close()方法传递两个可选参数: code(数字型的状态代码)和reason()一个文本字符串。
向服务器传递关于关闭连接的原因。

websocket知识

  • 下面是从stompjs官网摘录翻译的关键部分

初始化创建stomp实例

使用普通的websockt

  var client= Stomp.client("ws://localhost:61614/stomp");
  
  Stomp.client(url, protocols) //protocols可以是字符串或数组
  默认protocols['v10.stomp', 'v11.stomp']

使用自定义的websocket

  • stompjs默认使用浏览器的WebSocket类来生成websocket
  • 考虑到浏览器不支持/浏览器websocket类名不叫WebSocket
  • 使用Stomp.over(ws)处理这种情况
var ws = new SockJS(url);//sockjs不支持ws://这种url
var client = Stomp.over(ws);
//注意 使用Stomp.over时,里面传的是遵守WebSocket定义的对象

建立连接

  • 前面STOMP client创建好后,需要使用实例的connect方法
------ 方式1
client.connect(login, passcode, connectCallback);
client.connect(login, passcode, connectCallback, errorCallback);
client.connect(login, passcode, connectCallback, errorCallback, host);
//前俩参数是string,后俩参数是object
------- 方式2
 client.connect(headers, connectCallback);
 client.connect(headers, connectCallback, errorCallback);

//一旦使用这种形式 就必须要有login和passcode(未验证,文档上这么写的)
var headers = {
      login: 'mylogin',
      passcode: 'mypasscode',
      // additional header(比如token之类的,往后写)
      'client-id': 'my-client-id'
    };
client.connect(headers, connectCallback)

断开连接

  client.disconnect(function() {
    alert("See you next time!");
  };

心跳

  • 默认心跳10s
client.heartbeat.outgoing = 20000; // client will send heartbeats every 20000ms
client.heartbeat.incoming = 0;     // client does not want to receive heartbeats from the server
//依靠setInterval来保持心跳

发消息

// 目标地址,请求头(可以是空对象),请求体(string,想发对象可以用json字符串)
client.send("/queue/test", {priority: 9}, "Hello, STOMP");

收消息

  • STOMP client订阅地址后才能收消息
//client.subscribe会返回一个对象(带id属性以及unsubscribe()方法),
var subscription = client.subscribe("/queue/test", callback);
  • 第三个参数可以给订阅地址实例加自定义id,也可以自定义请求头 image.png
  • headers看着更像是限定,不合规定的数据不收(没太看懂) image.png

封装websocket

  • 参考网上一些文章融合的
// websocket.js
/**
 * 使用方法
 * var ws=new Socket(url,事件接收回调函数)
 * ws.close()
 * 由于重连后socket的值是new一个新的WebSocket对象,所以new Socket得到的实例里的Socket属性和重连后的Socket不是一个东西,
 *
 */

export class Socket {
  Socket = "";
  setIntervalWesocketPush = null;
  URL = "";
  reconnectTime = 0;
  limitTime = 10;
  onmessageWS;
  constructor(url, onmessageWS) {
    this.URL = url;
    this.onmessageWS = (val) => {
      if (val.data === "pong") {
        console.log(val.data);
      }
      onmessageWS(val);
    };
    this.createSocket();
  }

  /**建立websocket连接 */
  createSocket() {
    // Socket && Socket.close()
    if (!this.Socket) {
      console.log("建立websocket连接");
      this.Socket = new WebSocket(this.URL);
      this.Socket.onopen = this.onopenWS;
      this.Socket.onmessage = this.onmessageWS;
      this.Socket.onerror = this.onerrorWS;
      this.Socket.onclose = this.oncloseWS;
    } else {
      console.log("websocket已连接");
    }
  }

  /**打开WS之后发送心跳 */
  onopenWS = () => {
    this.reconnectTime = 0;
    this.sendPing();
  };

  /**连接失败重连 */
  onerrorWS = () => {
    this.Socket.close();
    clearInterval(this.setIntervalWesocketPush);
    console.log("连接失败重连中");

    if (this.Socket.readyState !== 3) {
      this.reconnectTime++;
      this.Socket = null;
      if (this.reconnectTime < this.limitTime) {
        this.createSocket(URL);
      } else {
        console.log("超出尝试次数");
      }
    }
  };

  /**
   * 发送数据但连接未建立时进行处理等待重发
   * @param {any} message 需要发送的数据
   */
  connecting = (message) => {
    setTimeout(() => {
      if (this.Socket.readyState === 0) {
        this.connecting(message);
      } else {
        this.Socket.send(JSON.stringify(message));
      }
    }, 1000);
  };

  /**
   * 发送数据
   * @param {any} message 需要发送的数据
   * readyState
   * 0 - 表示连接尚未建立。
   * 1 - 表示连接已建立,可以进行通信。
   * 2 - 表示连接正在进行关闭。
   * 3 - 表示连接已经关闭或者连接不能打开。
   */
  sendWSPush = (message) => {
    if (this.Socket !== null && this.Socket.readyState === 3) {
      this.Socket.close();
      this.createSocket();
    } else if (this.Socket.readyState === 1) {
      this.Socket.send(JSON.stringify(message));
    } else if (this.Socket.readyState === 0) {
      this.connecting(message);
    }
  };

  /**断开重连 */
  oncloseWS = () => {
    clearInterval(this.setIntervalWesocketPush);
    console.log("websocket已断开....正在尝试重连");
    if (this.Socket.readyState !== 2) {
      this.reconnectTime++;
      this.Socket = null;
      if (this.reconnectTime < this.limitTime) {
        this.createSocket(URL);
      } else {
        console.log("超出尝试次数");
      }
    }
  };
  /**发送心跳
   * @param {number} time 心跳间隔毫秒 默认25s
   * @param {string} ping 心跳名称 默认字符串ping
   */
  sendPing = (time = 25000, ping = "ping") => {
    clearInterval(this.setIntervalWesocketPush);
    this.Socket.send(ping);
    this.setIntervalWesocketPush = setInterval(() => {
      this.Socket.send(ping);
    }, time);
  };

  /**关闭socket */
  close() {
    this.Socket.close();
  }
}