thinkjs3 websocket 小结

WebSocket

对于 WebSocket 目前 ThinkJS 支持了 socket.io、ws 对其进行了一些简单的包装。

开启 WebSocket


// socket.io 参考 https://thinkjs.org/zh-cn/doc/3.0/websocket.html
在集群环境中,WebSocket 要求使用粘性会话,来确保给定客户端请求命中相同的 worker,否则其握手机制将无法正常工作。 为了实现这一点,需要开启 stickyCluster 配置。

为了保证性能,stickyCluster 功能默认是关闭的,项目如果需要开启,可以修改配置文件 src/config/config.js

module.exports = {
  stickyCluster: true,
  // ...
};

与此同时,ThinkJS将websocket封装为think-websocket,但是需要在项目目录下执行

$ npm install -s think-websocket

来安装模块

配置 WebSocket

WebSocket 是以 extend 的形式集成到 ThinkJS 的,首先要配置 src/config/extend.js:

const websocket = require('think-websocket');

module.exports = [
  // ...
  websocket(think.app),
];

WebSocket 的各个实现是以 adapter 的形式存在的,以 socket.io 为例(使用 think-websocket-socket.io 进行了封装),在 src/config/adapter.js 中配置如下:

const socketio = require('think-websocket-socket.io');
exports.websocket = {
  type: 'socketio',
  common: {
    // common config
  },
  socketio: {
    handle: socketio,
    // allowOrigin: '127.0.0.1:8360',  // 默认所有的域名都允许访问
    path: '/socket.io',             // 默认 '/socket.io'
    adapter: null,                  // 默认无 adapter
    messages: {
      open: '/socket/open',
      addUser: '/socket/addUser'
    }
  }
}

事件到 Action 的映射

socket.io 为例,ThinkJS 遵循了 socket.io 服务端和客户端之间通过事件来交互的机制,这样服务端需要将事件名映射到对应的 Action,才能响应具体的事件。事件的映射关系配置在 messages 字段,具体如下:

exports.websocket = {
  // ...
  socketio: {
    // ...
    messages: {
      open: '/socket/open',       // 建立连接时处理对应到 socket Controller 下的 open Action
      close: '/socket/close',     // 关闭连接时处理的 Action
      addUser: '/socket/addUser', // addUser 事件处理的 Action
    }
  }
}

其中 openclose 事件名固定,表示建立连接和断开连接的事件,其他事件均为自定义,项目里可以根据需要添加。

服务端 Action 处理

通过配置事件到 Action 的映射后,就可以在对应的 Action 作相应的处理。如:
src\controller\socket.js

module.exports = class extends think.Controller {

  constructor(...arg) {
    super(...arg);
  }

  openAction() {
    this.emit('opend', 'This client opened successfully!')
    this.broadcast('joined', 'There is a new client joined successfully!')
  }

  addUserAction() {
    console.log('获取客户端 addUser 事件发送的数据', this.wsData);
    console.log('获取当前 WebSocket 对象', this.websocket);
    console.log('判断当前请求是否是 WebSocket 请求', this.isWebsocket);
  }
}

emit

Action 里可以通过 this.emit 方法给当前 socket 发送事件,如:

module.exports = class extends think.Controller {

  constructor(...arg) {
    super(...arg);
  }

  openAction() {
    this.emit('opend', 'This client opened successfully!')
  }
}

broadcast

Action 里可以通过 this.broadcast 方法给所有的 socket 广播事件,如:

module.exports = class extends think.Controller {

  constructor(...arg) {
    super(...arg);
  }

  openAction() {
    this.broadcast('joined', 'There is a new client joined successfully!')
  }
}

客户端示例

客户端示例代码如下:




// websocke 参考: https://github.com/thinkjs/think-websocket-ws

ThinkJS 3.X's ws adapter for websocket.

Install

npm install think-websocket-ws --save

How to Config

WebSocket 是以 extend 的形式集成到 ThinkJS 的,首先要配置 src/config/extend.js: (同socket.io, 官方文档遗漏)

const websocket = require('think-websocket');

module.exports = [
  // ...
  websocket(think.app),
];

Edit config file src/config/adapter.js, add options:

const ws = require('think-websocket-ws');
exports.websocket = {
  type: 'ws',
  common: {
    // common config
  },
  ws: {
    handle: ws,
    path: '/ws',
    messages: [{
      close: '/ws/close',
      open: '/ws/open',
      addUser: '/ws/addUser'
    }]
  }
}

More options see at ws doc.

Edit config file src/config/config.js, add options:

module.exports = {
  // ...
  stickyCluster: true
  // ...
}

Work with Action

// server  src\controller\ws.js
module.exports = class extends think.Controller {
  constructor(...arg) {
    super(...arg);
  }
  openAction() {
    console.log('ws open');
    return this.success();
  }
  closeAction() {
    console.log('ws close');
    return this.success();
  }
  addUserAction() {
    console.log('addUserAction ...');
    console.log(this.wsData); // this.req.websocketData, 'thinkjs'
    console.log(this.websocket); // this.req.websocket, websocket instance
    console.log(this.isWebsocket); // this.isMethod('WEBSOCKET'), true
    return this.success();
  }
}

// client
var ws = new WebSocket('ws://127.0.0.1:8360/ws');

ws.onopen = function() {
  console.log('open...');
}

ws.onerror = function(evt) {
  console.log(evt);
}

ws.onmessage = function(data) {
  console.log(data);
}

$('.send').on('click', function(evt) {
  var username = $.trim($('.usernameInput').val());
  var room = $.trim($('.roomInput').val());
  ws.send(JSON.stringify({
    event: 'addUser',
    data: {
      username: username,
      room: room
    }
  }));
});

emit

You can emit event to the current socket in Action through this.emit:

  // server
  module.exports = class extends think.Controller {
    constructor(...arg) {
      super(...arg);
    }
    openAction() {
      this.emit('opend', 'This client opened successfully!');
      return this.success();
    }
  }

  // client
  ws.onmessage = function(data) {
    data = JSON.parse(data.data);
    console.log(data.event); // opend
    console.log(data.data);  // This client opened successfully!
  }

broadcast

You can broadcast event to all sockets in Action through method this.broadcast:

  // server
  module.exports = class extends think.Controller {
    constructor(...arg) {
      super(...arg);
    }
    openAction() {
      this.broadcast('joined', 'There is a new client joined successfully!');
      return this.success();
    }
  }

  // client
  ws.onmessage = function(data) {
    data = JSON.parse(data.data);
    console.log(data.event); // joined
    console.log(data.data);  // There is a new client joined successfully!
  }

server端连接多客户端代码示例

const Base = require('./base.js');

const sockets = {};

module.exports = class extends Base {
  constructor(...arg) {
    super(...arg);
  }
  openAction() {
    console.log('ws open');
    this.emit('opend', 'This client opened successfully!')
    this.broadcast('joined', 'There is a new client joined successfully!');
    return this.success();
  }
  closeAction() {
    console.log('ws close');
    return this.success();
  }

  taskBeginAction() {
    console.log('向客户端下达执行任务的指令');
    console.log(sockets,"--------");
    // http://127.0.0.1:8360/ws/taskBegin?name=555
    var name = this.get("name")
    console.log(name)
    sockets[name].emit('taskBegin la', {'name':'task11'})
    return this.success();
  }

  addUserAction() {
    console.log('addUserAction ...');
    sockets[this.wsData.data.username] = this;
    // console.log(this.wsData,111); // this.req.websocketData, 'thinkjs'
    // console.log(this.websocket,222); // this.req.websocket, websocket instance
    // console.log(this.isWebsocket,333); // this.isMethod('WEBSOCKET'), true 
    return this.success();
  }
};

你可能感兴趣的:(thinkjs3 websocket 小结)