打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
WebSocket

WebSocket

项目里经常要要使用 WebSocket 来实现聊天等功能,ThinkJS 支持多种 WebSocket 库,如:socket.iosockjs 等,并对这些库进行了一些简单的包装,让使用的接口一致。

开启 WebSocket

WebSocket 功能默认是关闭的,项目如果需要开启,可以修改配置文件 src/common/config/websocket.js

export default {  on: false, //是否开启 WebSocket  type: "socket.io", //使用的 WebSocket 库类型,默认为 socket.io  allow_origin: "", //允许的 origin  adp: undefined, // socket 存储的 adapter,socket.io 下使用  path: "", //url path for websocket  messages: {    // open: "home/websocket/open",  }};

需要将配置 on 的值修改为 true,并重启 Node.js 服务。

事件到 Action 的映射

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

export default {  messages: {    open: "home/socketio/open", // WebSocket 建立连接时处理的 Action    close: "home/socketio/close", // WebSocket 关闭时处理的 Action    adduser: "home/socketio/adduser", //adduser 事件处理的 Action  }}

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

Action 处理

通过上面配置事件到 Action 的映射后,就可以在对应的 Action 作相应的处理。如:

export default class extends think.controller.base {  /**   * WebSocket 建立连接时处理   * @param  {} self []   * @return {}      []   */  openAction(self){    var socket = self.http.socket;    this.broadcast("new message", {      username: socket.username,      message: self.http.data    });  }}

emit

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

export default class extends think.controller.base {  /**   * WebSocket 建立连接时处理   * @param  {} self []   * @return {}      []   */  openAction(self){    var socket = self.http.socket;    this.emit("new message", "connected");  }}

broadcast

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

export default class extends think.controller.base {  chatAction(self){    var socket = self.http.socket;    //广播给除当前 socket 之外的所有 sockets    this.broadcast("new message", {msg: "message", username: "xxx"});  }}

:broadcast 方法默认是給除去当前 socket 的所有 sockets 发送事件,如果想包含当前的 socket,可以设置第三个参数值为 true

export default class extends think.controller.base {  chatAction(self){    var socket = self.http.socket;    //广播给所有的 sockets,包含当前的 socket    this.broadcast("new message", {msg: "message", username: "xxx"}, true);  }}

socket 对象

Action 里可以通过 this.http.socket 拿到当前的 socket 对象。

事件数据

Action 里可以通过 this.http.data 拿到发送过来事件的数据。

socket.io

socket.io 对 WebSocket 前后端都有封装,使用起来非常方便。

io 对象

在 Action 里可以通过 this.http.io 来获取 io 对象,该对象为 socket.io 的一个实例。

io 对象包含的方法请见 http://socket.io/docs/server-api/#server()

设置 path

设置被 socket.io 处理的路径,默认为 /socket.io。如果需要修改,可以修改下面的配置:

/* src/common/config/websocket.js */export default {  type: "socket.io",  adapter: {    "socket.io": {      path: "/other_path"    }  }}

:服务端修改了处理的路径后,客户端也要作对应的修改。

设置 adapter

使用多节点来部署 WebSocket 时,多节点之间可以借助 Redis 进行通信,这时可以设置 adapter 来实现。

/* src/common/config/websocket.js */import redis from "socket.io-redis";export default {  type: "socket.io",  adapter: {    "socket.io": {      adp: function(){        return redis({ host: "localhost", port: 6379 });      }    }  }}

具体请见 http://socket.io/docs/using-multiple-nodes/

socket.io client

浏览器端需要引入 socket.io client,下载地址为:http://socket.io/download/

var socket = io("http://localhost:8360");//发送事件socket.emit("name", "data");//监听事件socket.on("name", function(data){})

也可以直接引入一个 CDN 地址:http://s4.qhimg.com/static/535dde855bc726e2/socket.io-1.2.0.js

校验用户登录

WebSocket 建立连接时可以拿到 cookie,所以可以在 open 对应的 Action 里校验用户是否登录。如:

export default class extends think.controller.base {  * openAction(){    let userInfo = yield this.session("userInfo");    if(think.isEmpty(userInfo)){    }  }}

聊天代码示例

聊天示例代码请见:https://github.com/75team/thinkjs2-demos/tree/master/websocket-socket.io

SockJS

配置

使用 SockJS 库,需要将配置里的 type 修改为 sockjs,如:

export default {  type: "sockjs"}

sockjs 对象

Action 里可以通过 this.http.sockjs 拿到 sockjs 对象,该对象为 SockJS 类的一个实例。

设置 path

设置被 SockJS 处理的路径,默认为 /sockjs,可以通过下面的配置修改:

export default {  path: "/websocket"}

SockJS client

浏览器端需要引入 SockJS client,下载地址为:https://github.com/sockjs/sockjs-client

SockJS client 并没有做什么封装,所以需要额外做一层包装,变成事件的方式,以便跟包装后的服务端对应。包装方式参考如下:

SockJS.prototype.emit = function(event, data){    this.send(JSON.stringify({event: event, data: data}));  }SockJS.prototype.events = {};SockJS.prototype.on = function(event, callback){  if(!(event in this.events)){    this.events[event] = [];  }  this.events[event].push(callback);}SockJS.prototype.onmessage = function(e) {  var data = JSON.parse(e.data);  var callbacks = this.events[data.event] || [];  callbacks.forEach(function(callback){    callback && callback(data.data);  })};SockJS.prototype.onopen    = function()  {  this.onmessage(JSON.stringify({data: {event: "open"}}));};SockJS.prototype.onclose   = function()  {  this.onmessage(JSON.stringify({data: {event: "close"}}));};

通过上面的包装后就可以通过事件的方式来接收和发送消息了,如:

var socket = new SockJS("/sockjs"); //这里的路径必须和配置里相同,如果没有配置则为 /sockjs//监听事件socket.on("add user", function(data){});//发送事件socket.emit("new message", "xxx");

校验用户登录

SockJS 为了安全,在建立连接时不提供相关的 cookie,所以无法通过 cookie 来校验用户是否登录。可以先在页面里输出一个 token,建立连接时将该 token 发送用来校验是否已经登录。具体请见:https://github.com/sockjs/sockjs-node#authorisation

聊天代码示例

聊天示例代码请见:https://github.com/75team/thinkjs2-demos/tree/master/websocket-sockjs

nginx 反向代理

nginx 从 1.3.13 版本开始支持反向代理 WebSocket 请求,如果在项目中使用,需要在 nginx 配置文件中添加如下的配置:

proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection "upgrade";

: 使用 thinkjs 命令创建项目时,会自动创建 nginx 配置文件,并且配置文件已经包含了上面 2 个配置,可以直接使用。

nginx 代理 WebSocket 请求的文档请见 http://nginx.org/en/docs/http/websocket.html

获取当前所有的 WebSocket 连接对象

可以通过 thinkCache(thinkCache.WEBSOCKET) 来获取所有的 WebSocket 连接对象,数组格式。

如何实现私聊

ThinkJS 目前还没有私聊的机制,项目里可以通过获取所有的 WebSocket 连接然后找到对应的连接进行。

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
有关WebSocket必须了解的知识
干货 | 使用socket.io实现WebSocket即时通讯
Linux下多路复用IO接口 epoll select poll 的区别
直播软件开发,主动的方式有很多种,你选哪个
使用C++ 实现的 websocket 客户端 (基于easywsclient)
九种跨域方式实现原理
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服