如何使用Express的post请求来发出Socket.io或Sockjs?

8
我知道这个问题有点棘手,但问题来自三星2010/2011智能电视(和蓝光播放器;当然2012模拟器运行良好)。我将源码和包中的简单聊天示例移植到智能电视应用程序中。它们都回退到JSONP轮询,但仅从SmartTV应用程序中可以向服务器发出/推送一次。从服务器接收消息可能会多次而没有任何问题。在三星D论坛上寻找答案后(当然没有任何信息),我认为解决这个问题最快的方法是部署一个Express服务器,接收POST数据并执行JSON.parse,然后在服务器内部发布Socket.io/Sockjs。

有人能给我展示一个简单的代码样本,让我从那里开始吗?非常感谢。

我很快编写了代码,但似乎它无法工作:

lib/server.js

var express = require('express')
  , app = express.createServer()
  , io = require('socket.io').listen(app);

app.listen(80);

app.use(express.bodyParser());

app.get('/', function (req, res) {
  res.sendfile('/var/www/mpgs_lite_v3/index.html');
});

app.post('/', function(req, res){
  console.log(req.body);
  io.sockets.emit('my other event', req.body);
  res.redirect('back');
});

io.sockets.on('connection', function (socket) {
  //socket.emit('news', { hello: 'world' });
  socket.on('my other event', function (data) {
    console.log(data);
  });
});

index.html

<html>
<head>
<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io.connect('http://localhost');
  socket.on('news', function (data) {
    console.log(data);
    socket.emit('my other event', { my: 'data' });
  });
</script>
</head>
<body>
<form method="post" action="/">
     <input type="hidden" name="_method" value="put" />
     <input type="text" name="user[name]" />
     <input type="text" name="user[email]" />
     <input type="submit" value="Submit" />
 </form>
</body>
</html>

“我的其他事件”似乎没有接收到任何东西。

我找到了解决方案。只需将“我的其他事件”中的任何内容移动到另一个函数中,并让post和emit都调用它。虽然这个问题解决了,但我需要管理连接在其他行上的套接字。 - user1045217
4个回答

16

更新: 我已经为您更新了示例以使其更加完整。在此之前,我没有 app.listen,这里还有一个客户端脚本,它表明它确实可以正常工作:

<!doctype html>
<html>
    <head>
        <script src="//www.google.com/jsapi"></script>
        <script src="/socket.io/socket.io.js"></script>
        <script>google.load("jquery", "1.7.1")</script>
        <script>
            var socket = io.connect("localhost", {port: 3000});
            socket.on("foo", function(message) { console.log("foo: ", message) });
            $(function() {
                $("button").click(function() {
                    $.post("/foo", { message: $("input").val() });
                });
            });
        </script>
    </head>
    <body>
        <input type=text>A message</input>
        <button>Click me!</button>
    </body>
</html>

现在服务器有一个app.listen指令:

var express = require("express"),
    app = express.createServer(),
    io = require("socket.io").listen(app)
    index = require("fs").readFileSync(__dirname + "/index.html", "utf8");

app.use(express.bodyParser());

app.get("/", function(req, res, next) {
    res.send(index);
});

app.post("/foo", function(req, res, next) {
    io.sockets.emit("foo", req.body);
    res.send({});
});

app.listen(3000);

使用方法:

node app.js

前往 http://localhost:3000/ 并单击按钮。检查控制台以获取输出。


Linus,我尝试的是在服务器上发出一些内容(self-emit,express post to socket.io emit)。在三星智能电视上,服务器向客户端推送机制运行得非常好(我个人会说是愚蠢的电视)。如果我在app.listen(3000);之后放置io.sockets.on("foo", function(message) { // emit another to client or just log on console },它将不起作用。 - user1045217
对于较新版本的Express:var express = require('express'),http = require('http'); var bodyParser = require('body-parser'); var app = express(); var server = http.createServer(app);var io = require('socket.io').listen(server); server.listen(my_port); - Ahmad Muzakki

2

基于SockJS express example,server.js可能如下:

var express = require('express');
var sockjs  = require('sockjs');
// 1. 回显sockjs服务器 var sockjs_opts = {sockjs_url: "http://cdn.sockjs.org/sockjs-0.2.min.js"};
var sockjs_echo = sockjs.createServer(sockjs_opts); connections = {}; sockjs_echo.on('connection', function(conn) { console.log(conn.id); connections[conn.id] = conn conn.on('close', function() { delete connections[conn.id]; });
// 回显。 conn.on('data', function(message) { conn.write(message); }); });
// 2. Express服务器 var app = express.createServer(); sockjs_echo.installHandlers(app, {prefix:'/echo'});
console.log(' [*] Listening on 0.0.0.0:9999' ); app.listen(9999, '0.0.0.0');
app.get('/', function (req, res) { res.sendfile(__dirname + '/index.html'); });
app.post("/send", function(req, res, next) { for(var id in connections) { connections[id].write('received POST'); } res.send({}); });

要测试,请在本地打开浏览器访问localhost:9999并运行:

curl localhost:9999/send -X POST

我很欣赏你的工作。但是你的例子在我的电脑上好像不能运行。0. 我没有看到“received POST”出现在控制台上。1. 我创建了一个简单的客户端html(index.html),只是进行了一个post请求。最初我以为它会挂载在localhost:9999/echo/,但实际上它是在localhost:9999/上。2. 从html发起的post也遇到了同样的问题。 - user1045217

1

只需删除此注释 //socket.emit('news', { hello: 'world' }); 改为 socket.emit('news', { hello: 'world' });

这将起作用,因为它通过“news”发送数据,而您正在使用我的其他事件进行监听,而不是“news”,或者您可以仅使用“my other event”进行监听。


-1
我不知道这是否有帮助,但你可以根据你的浏览器在客户端上创建一个emit抽象,然后在服务器上创建一个单独的get函数来处理请求,方式与socket.on回调相同。为了知道信息应该发送到哪里,建议使用一些键,在服务器上存储在哈希表中,在客户端上存储在本地存储中。
对于客户端:
var emit = function(event, options) {
    if ("WebSocket" in window) {
        socket.emit(event, options);
        console.log("emited via WebSocket");
    } else {
        $.post("http://localhost/emit/" + event, options);
        console.log("emited via AJAX");
    }
}

emit("echo", {
    key: localStorage.getItem("key"),
    data: {
        hello: "world"
    }
});

socket.on("response", function(data) {
    console.log(data.hello); //will print "world"
});

对于服务器:

var sockets = {};
var echo_handler = function(a) {
    var socket = sockets[a.key];
    var data = a.data;
    socket.emit("response", data);
}

app.post("/emit/:event", function(req, res) {
    var event = req.params.event;
    switch (event) {
    case "echo":
        var a = {
            key: req.param("key"),
            data: req.param("data")
        }
        echo_handler(a);
        break;
    }
});

io.sockets.on("connection", function(socket) {
    socket.on("connect", function(data) {
        sockets[data.key] = socket;
    });
    socket.on("echo", echo_handler);
});

另一种方法是切换到Sockjs并使用他们的patch

如果有人对Socket.IO有更好的解决方案,将不胜感激,因为我已经深入项目中了,现在切换到Sockjs来替代Socket.IO已经太晚了,而且这个解决方案也不符合我的口味 :( .


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接