一直以来 HTTP 协议都是使用「请求/响应」的模型,在 Web 应用越来越复杂的今天,这种模型的限制越来越明显。

很多场景下,我们想要服务器主动发送通知给浏览器,甚至我们想在浏览器中实现一个实时对战的网络游戏。这个时候 HTML5 规范中的 WebSocket 可以很好地满足我们的需求。

对于使用 LeanEngine 的用户,我们也可以直接在 LeanEngine 环境中使用 WebSocket,来构建应用了。下面我们以 LeanEngine NodeJS 运行时环境为例,实现一个 WebSocket echo server(echo server 是指返回任何接收到信息的服务)。

创建应用

我们可以使用 avoscloud new 命令来创建一个新的 LeanEngine 应用,但是简单起见,我们的还是直接手动创建我们的项目。

首先将下面的内容放到项目根目录的 package.json 文件中:

{
  "dependencies": {
    "ejs": "^2.3.2",
    "express": "^4.13.0",
    "express-ws": "^0.2.6",
    "leanengine": "^0.1.4"
  }
}

然后执行npm install来安装依赖。

ws16 是 Node.js 一个比较常用的 WebSocket 实现模块。而 express-ws 是对其简单的封装,方便在 express 中使用。

之后创建 server.js 文件,作为应用的入口文件。在这个文件中,我们初始化 express 与 LeanCloud SDK:

var express = require("express");
var AV = require('leanengine');

// init LeanEngine
var PORT = parseInt(process.env.LC_APP_PORT || 3000);
var APP_ID = process.env.LC_APP_ID;
var APP_KEY = process.env.LC_APP_KEY;
var MASTER_KEY = process.env.LC_APP_MASTER_KEY;
AV.initialize(APP_ID, APP_KEY, MASTER_KEY);

// init express
var app = express();
app.set('view engine', 'ejs');
app.use(AV.Cloud);

// start server
app.listen(PORT);

这样一个最基本的 LeanEngine 应用就已经实现了,在此之上我们可以增加自己的路由处理与 LeanEngine 的 CloudFunc 等功能,但这不是这篇文章的重点,在此略过。

express-ws 是作为 express 的中间件实现的,之后我们需要安装此中间件:

var expressWs = require('express-ws');
expressWs(app);

之后就可以使用 app.ws 方法来注册 WebSocket 路由请求了:

app.ws('/echo', function(ws, req) {
  ws.on('message', function(msg) {
    ws.send(msg);
  });
});

这里只是简单的将收到的请求发送回客户端,你也可以实现其他自定义的操作。

使用 LeanCloud 提供的命令行工具,我们可以将应用部署到服务器上:avoscloud deploy && avoscloud publish

wscat7 是一个基于 Node.js 实现的命令行工具,可以用来测试我们的 echo server。使用 npm install wscat -g 来安装此工具,之后 wscat -c ws://websocket.avosapps.com (将 websocket 替换成自己在 LeanCloud 注册的二级域名)连接自己的服务:

$ wscat -c ws://websocket.avosapps.com/echo
connected (press CTRL+C to quit)
> Hello WebSocket!
< Hello WebSocket!
>

如果没有问题的话,基于 LeanEngine 的 WebSocket 服务就搭建成功了。

以上代码参见 Github Demo17,效果参考46http://websocket.avosapps.com46

备注:LeanCloud 还提供实时通讯43服务,相比自己使用 WebSocket,它能帮你更加轻松地实现实时聊天等功能,并且你也不用担心部署、断线重连与自动扩容等问题。

2 人赞了这个帖子.

哇哇哇哇哇~终于支持了,good job

从最后一句来看,还是使用实时通讯好
就是实时通讯学习成本略高一些

你好。能用socket.io吗?socket.io和express可以结合使用的。express-ws我看了一下star仅36个。

另外express-ws能伸缩到多台服务器吗?比如有2个节点AB,一个客户连接到A,另外一个连接到B,能不能转发消息?不是太需要实时通讯。

不能用socket.io,咨询了一下官方的同学,他们说暂不支持,我实测了一下,也是如此

请问怎么才能让web socket和lean cloud的用户机制结合起来使用呢? 因为连接web socket也需要进行用户验证,但是ws的request里并不能取到user.

可以在创建 websocket 的时候把 session token 传过来,做验证之后在创建 websocket
也可以后续自己手动验证

@HarrysDad express-ws 这个模块只是简单的封装了一下 ws3 这个模块,这个模块有数千的 star 的。

socket.io 也是可以使用的。伸缩到多台机器需要自己写代码来实现。

您好,应该是支持 socket.io 的,如果您测试遇到问题,麻烦发一下遇到的问题,以及相关代码,我们尽快解决!

请问有没有简单的部署教程啊,我在本地测试正常,部署上线就不行了。
我是按照socket.io官方的demo这样写,
服务端:
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);

server.listen(80);  //部署上线的时候把这行给注释掉了,是因为刚开始没注释也错误
io.on() ...

客户端:
本地测试用的:

var socket = io.connect('localhost:3000');

部署时候改成了:

var socket = io.connect('felbry.leanapp.cn');

然后访问在console界面就是:
Request URL:http://felbry.leanapp.cn/socket.io/?EIO=3&transport=polling&t=LOnJkAP (not found)

是不是leanengine自己创建的有服务器,所以我自己创那个server没什么用?

请问确实是支持socket.io么?我测试在本机的时候可以连接,但是部署到 lean cloud 上后就连接不上了

let server = require('http').createServer(app);
let io = require('socket.io')(server);
// let io = require('socket.io')();
let redis = require('socket.io-redis');
io.adapter(redis(process.env['REDIS_URL_Game_001']));
io.on('connection', function(){
  console.log('socket.io connection');
 });

server.listen(PORT, function () {
  console.log('Node app is running, port:', PORT);

  // 注册全局未捕获异常处理器
  process.on('uncaughtException', function(err) {
    console.error("Caught exception:", err.stack);
  });
  process.on('unhandledRejection', function(reason, p) {
    console.error("Unhandled Rejection at: Promise ", p, " reason: ", reason.stack);
  });
});

有没有解决,能不能用socket.io

你好,是不是你调用了 app.listen,而没有调用 http.listen,这样当然找不到了。

你好,我使用命令行工具创建的 nodejs 项目,修改了 server.js ,内容如下:

'use strict';

var AV = require('leanengine');

AV.init({
  appId: process.env.LEANCLOUD_APP_ID,
  appKey: process.env.LEANCLOUD_APP_KEY,
  masterKey: process.env.LEANCLOUD_APP_MASTER_KEY
});

// 如果不希望使用 masterKey 权限,可以将下面一行删除
AV.Cloud.useMasterKey();

var http = require('http').Server(require('./app'));
var io = require('socket.io')(http);

io.on('connection', function(socket){
  console.log('a user connected');
  socket.on('disconnect', function(){
    console.log('user disconnected');
  });
});

// 端口一定要从环境变量 `LEANCLOUD_APP_PORT` 中获取。
// LeanEngine 运行时会分配端口并赋值到该变量。
var PORT = parseInt(process.env.LEANCLOUD_APP_PORT || 3000);
http.listen(PORT, function () {
  console.log('Node app is running, port:', PORT);

  // 注册全局未捕获异常处理器
  process.on('uncaughtException', function(err) {
    console.error("Caught exception:", err.stack);
  });
  process.on('unhandledRejection', function(reason, p) {
    console.error("Unhandled Rejection at: Promise ", p, " reason: ", reason.stack);
  });
});

部署到线上是没有问题的。

没有啊,我是调用的 http.listener

let server = require('http').createServer(app);
...
server.listen(PORT, function () {

能不能把你的 app.js 贴一下出来,可能问题出在那里。

app.js 没有修改。

部署到了这里:http://aaaaa.avosapps.com 可以测试一下(请尽快测试,之后可能会被覆盖测试其他的代码)

我的有修改,我不是用控制台创建的项目,所以有可能有不同,麻烦贴下出来吧,我对比一下,找一下原因

推到 GitHub 上了:https://github.com/aisk/node-js-getting-started/tree/socket-io-demo

注意是 socket-io-demo 这个分支。

@zengshi @Felbry @zmwl