【问题标题】:Sending socket.io instance to express route发送 socket.io 实例以表达路由
【发布时间】:2016-04-27 08:28:48
【问题描述】:

我正在尝试创建一个 nodejs 应用程序,该应用程序将使用其 API 在各种网站中进行搜索。一旦使用 socket.io 从这些 API 接收到结果,结果将立即发送给客户端。然后前端将使用 jQuery 添加这些结果。

实现这一点的最佳方法是什么?

到目前为止我已经尝试过:

示例代码 1

起初我为 express 创建了一个中间件,将套接字添加到请求中,例如 -

var socketMiddleWare = function(req, res, next){
  io.on('connection', function(socket){
    console.log(io.engine.clientsCount + " clients connected.");
    req.socket = socket;
    
    socket.on('disconnect', function(){
      console.log(io.engine.clientsCount + " clients after disconnec.");
    });
    
  });
  next();
};

然后将此中间件添加到我的路由中 -

app.use('/users', socketMiddleWare, users);

它可以工作,但问题是每次用户刷新页面时它都会创建多个事件监听器。

示例代码 2

然后我尝试了(示例代码)

io.on('connection', function(socket){
  console.log("user connected");
  global.socket = socket;
  socket.on('disconnect', function(){
    console.log("disconnect");
  });
  
  socket.on('my message', function(){
    console.log("My message received");
  });
});

在我的测试路线上我做到了

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  if(socket){
    socket.emit('response', 'nothing');
  }
  res.render('index', { title: 'Express' });
});

module.exports = router;

它解决了之前刷新时多个事件监听器的问题,但大多数时候它无法发出响应。甚至它发出我的浏览器也无法显示结果。在客户端我做了这样的事情-

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

socket.on('response', function(data){
    console.log(data);        
    document.getElementById("change").innerHTML += data;
});

我可以在浏览器控制台中看到响应,但我的浏览器会在更改消失之前显示更改几毫秒。

我认为主要问题是页面在建立套接字连接之前加载。

我目前正在学习 node.js 和 socket.io。所以请帮助我。

结论

我确实计划在未来使用 socket.io 添加社交网络功能,例如一对一消息、主页上的实时好友动态更新等。如果有任何好的文档或开源项目可以帮助我实现它,请告诉我。

我最近几天一直在寻找解决方案,但到目前为止还没有运气。我已准备好学习任何新方法或完全重写我的代码。

TL;DR

当用户客户端搜索项目时,当有新数据可用时,将内容推送到请求内容的客户端。通过其 API 处理来自“The Movie Database”和“TheTVDB.com”等网站的响应后,数据可用。

【问题讨论】:

    标签: javascript node.js express websocket socket.io


    【解决方案1】:

    您可以使用套接字的 ID 来跟踪将结果发送到哪个套接字。

    客户

    当用户随后搜索某些内容时,ID 将包含在查询参数中。

    <body>
        <form>
            <!-- Disable the search bar until the socket is connected -->
            <input type="search" name="q" placeholder="Search" disabled>
        </form>
        <div id="results"></div>
        <script src="/socket.io/socket.io.js"></script>
        <script>
            var resultsElement = document.querySelector("#results");
            var search = document.querySelector("form [type=search]");
            var socket = io("http://localhost:3000");
    
    
            socket.on("connect", function(){
                search.disabled = false;
            });
    
            socket.on("results", function(results){
                for(var i = 0;i < results.length;i++){
                    var result = document.createElement("div");
                    result.textContent = results[i];
                    resultsElement.appendChild(result);
                }
            });
    
            document.querySelector("form").addEventListener("submit", function(event){
                fetch("/search?socketID=" + encodeURIComponent(socket.id) + "&q=" + encodeURIComponent(search.value));
                event.preventDefault();
            });
        </script>
    </body>
    

    服务器

    当服务器接收到搜索请求时,它使用查询参数中发送的套接字 ID 获取套接字,并开始将结果发送回客户端。

    var app = require("http").createServer(handler);
    var io = require("socket.io")(app);
    var fs = require("fs");
    var url = require("url");
    app.listen(3000);
    
    function handler(req, res) {
        var query = url.parse(req.url, true).query;
        if(req.url.startsWith("/search")){
            var results = ["things", "stuff", "items"];
            // Server-side IDs have "/#" in front of them
            var socket = io.sockets.connected["/#" + query.socketID];
            if(socket){
                // Get and send "search results"
                var interval = setInterval(function(){
                    var popped = results.pop();
                    if(popped){
                        socket.emit("results", [query.q + " " + popped]);
                    }else{
                        clearInterval(interval);
                    }
                }, 1000);
            }
            res.writeHead(204);
            res.end();
        }else{
            fs.readFile(__dirname + "/index.html", function(err, data) {
                res.writeHead(200);
                res.end(data);
            });
        }
    }
    

    【讨论】:

    • 感谢您的回复。我的 gobal.socket 方法现在适用于我的设置。因为来自外部服务的 API 响应需要时间来处理,同时建立套接字连接。
    • 您是否测试过同时从两个地方进行搜索?只有一个套接字会得到结果。
    • 我只是尝试在我的 global.socket 代码中一次搜索两个地方,所有搜索结果都只推送到一个客户端。其他客户没有反应!谢谢@metarmask
    猜你喜欢
    • 2015-12-10
    • 2015-07-04
    • 1970-01-01
    • 2016-03-09
    • 1970-01-01
    • 2014-10-31
    • 1970-01-01
    • 2016-09-20
    • 1970-01-01
    相关资源
    最近更新 更多