Usando socket.io no Express 4 e / bin / www do express-generator

93

Então aqui está o negócio: estou tentando usar socket.io em um projeto expresso. Depois que o Express Js 4 foi lançado, eu atualizei meu express-generator e agora as funções iniciais do aplicativo vão para o ./bin/wwwarquivo, incluindo aqueles vars (conteúdo do arquivo www: http://jsfiddle.net/avMa5/ )

var server = app.listen(app.get('port'), function() {..}

(verifique até npm install -g express-generatorexpress myApp

Dito isso, vamos lembrar como o socket.io docs nos pede para dispará-lo:

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

Ok, mas eu não consigo fazer isso dentro do app.js, como recomendado. Isso deve ser feito em ./bin/www para funcionar. em ./bin/www isto é o que posso fazer para fazê-lo funcionar:

var io = require('socket.io')(server)

Ok, isso funciona, mas não posso usar o io var em qualquer outro lugar e realmente não quero colocar minhas funções socket.io no wwwarquivo.

Acho que esta é apenas uma sintaxe básica, mas não consigo fazer funcionar, nem mesmo usando module.exports = serverou server.exports = servernemmodule.exports.io = app(io) no arquivo www

Portanto, a questão é: como posso usar o socket.io tendo este arquivo / bin / www como ponto de partida do meu aplicativo?

user1576978
fonte
Você não tem que colocar a importação ./bin/www.. Basta colocá-lo no mesmo lugar, onde você var appestá.
alandarev
15
Eu gostaria que as pessoas parassem de sugerir express-io. Está desatualizado e não é mais mantido.
Ben Fortune
@Mritunjay obrigado, mas não resolveu: /
user1576978
@BenFortune, desculpe, vou manter isso em mente.
Mritunjay
@alandarev var app = express () ?? Eu realmente tentei, sem sucesso
user1576978

Respostas:

160

Tenho uma solução para disponibilizar socket.io em app.js.

app.js:

var express      = require( "express"   );
var socket_io    = require( "socket.io" );

// Express
var app          = express();

// Socket.io
var io           = socket_io();
app.io           = io;

(...)

// socket.io events
io.on( "connection", function( socket )
{
    console.log( "A user connected" );
});

module.exports = app;

// Or a shorter version of previous lines:
//
//    var app = require( "express"   )();
//    var io  = app.io = require( "socket.io" )();
//    io.on( "connection", function( socket ) {
//        console.log( "A user connected" );
//    });
//    module.exports = app;

bin / www:

(...)

/**
 * Create HTTP server.
 */

var server = http.createServer( app );


/**
 * Socket.io
 */

var io     = app.io
io.attach( server );

(...)

Dessa forma, você pode acessar a variável io em seu app.js e até mesmo disponibilizá-la para suas rotas definindo module.exports como uma função que aceita io como parâmetro.

index.js

module.exports = function(io) {
    var app = require('express');
    var router = app.Router();

    io.on('connection', function(socket) { 
        (...) 
    });

    return router;
}

Em seguida, passe io para o módulo após sua configuração:

app.js

// Socket.io
var io = socket_io();
app.io = io;

var routes = require('./routes/index')(io);
Gabriel Hautclocq
fonte
1
Eu sou novo no NodeJS. Você pode explicar o que exatamente está acontecendo nesta linha app.io = io;do app.jsarquivo
Aryak Sengupta
3
É simplesmente uma questão de colocar a variável io no objeto de aplicativo. Também pode ser: app.io = socket_io ();
Gabriel Hautclocq
7
"... e até disponibilizá-lo nas suas rotas, se quiser." Ok, mas como? Seria ótimo se você pudesse dar um exemplo de como fazer isso.
assustador,
2
Não é ruim anexar uma propriedade personalizada ao appobjeto? Melhor usar símbolos ou app.set().
Alexander Gonchiy
3
Por que app.io = ioquando você poderia usar no module.exports = { app, io }lugar
Manan Mehta
56

Uma abordagem um pouco diferente para iniciar socket.io , ela agrupa todos os códigos relacionados em um só lugar:

bin / www

/**
 * Socket.io
 */
var socketApi = require('../socketApi');
var io = socketApi.io;
io.attach(server);

socketApi.js

var socket_io = require('socket.io');
var io = socket_io();
var socketApi = {};

socketApi.io = io;

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

socketApi.sendNotification = function() {
    io.sockets.emit('hello', {msg: 'Hello World!'});
}

module.exports = socketApi;

app.js

// Nothing here

Desta forma, todo o socket.iocódigo relacionado em um módulo e função dele posso invocar de qualquer lugar no aplicativo.

Anatoly
fonte
4
Esta resposta merece mais votos positivos! Muito simples e limpo, ele mantém as rotas de socket fora do www , app.js e também fora do index.js (sim, fora do index.js ), este arquivo deve conter apenas rotas HTTP Express.
adelriosantiago
1
Incrível, muito limpo
sanket
3
Alguém pode atualizar isso para socket.io 2.0? Não está funcionando para mim. io.attach (servidor) e io.listen (servidor) lançam "não é possível ler a propriedade X de indefinido".
tsujp
1
Também falar com @tsujp mine funciona da mesma forma. Você tem que acessar a url certa e adicionar o cliente socket.io e você verá que funciona
Tamb
Estou com um problema semelhante ao @tsujp, estou usando o socket.io 2.3.0 e estou recebendoio.attach is not a function
raquelhortab
42

Acontece que realmente era um problema básico de sintaxe ... Peguei essas linhas neste tutorial de bate-papo do socket.io ...

em ./bin/www, logo depois var server = app.listen(.....)

var io = require('socket.io').listen(server);
require('../sockets/base')(io);

então agora eu crio o arquivo ../sockets/base.js e coloco este pequeno companheiro dentro dele:

module.exports = function (io) { // io stuff here... io.on('conection..... }

sim! Agora funciona ... Acho que realmente não tive outra opção a não ser iniciar o socket.io dentro de / bin / www, porque foi lá que meu servidor http foi iniciado. O objetivo é que agora eu possa construir funcionalidade de socket em outro (s) arquivo (s), mantendo a coisa modular, porrequire('fileHere')(io);

<3

user1576978
fonte
1
O problema é que você não pode fazer algo comoio.on('connection', function(socket) { res.render('connection.jade') });
Gofilord
3
@Gofilord é porque ele anula todo o propósito dos sockets ... o que você precisa é de roteamento regular que inclui renderização. Os sockets estão aqui apenas para enviar mensagens entre o cliente e o servidor sem solicitações http. talvez leia este artigo enterprisewebbook.com/ch8_websockets.html
Unispaw de
19

O antigo "expressjs", tudo está acontecendo no arquivo "app.js". Portanto, a ligação do socket.io ao servidor também acontece naquele arquivo. (BTW, ainda é possível fazer da maneira antiga e remover bin / www)

Agora com os novos expressjs, isso precisa acontecer no arquivo "bin / www".

Felizmente, javascript / requirejs facilitou a passagem de objetos. Como Gabriel Hautclocq apontou, socket.io ainda é "importado" em "app.js" e é anexado ao objeto "app" por meio de uma propriedade

app.io = require('socket.io')();

O socket.io é ativado conectando-se a ele no servidor em "bin / www"

app.io.attach(server); 

porque o objeto "app" é passado para "bin / www" anteriormente

app = require("../app");

É realmente tão simples quanto

require('socket.io')().attach(server);

Mas fazer isso da maneira "difícil" garante que app.io agora segure o objeto socke.io.

Agora, se você precisa desse objeto socket.io também em "routes / index.js" por exemplo, apenas use o mesmo princípio para passar esse objeto.

Primeiro em "app.js", faça

app.use('/', require('./routes/index')(app.io));

Em seguida, em "routes / index.js"

module.exports = function(io){
    //now you can use io.emit() in this file

    var router = express.Router();



    return router;
 }

Portanto, "io" é injetado em "index.js".

Zhe Hu
fonte
9

Atualização da resposta de Gabriel Hautclocq :

No arquivo www, o código deve aparecer como o seguinte devido às atualizações com Socket.io. Anexar agora é Ouvir.

/**
 * Create HTTP server.
 */

var server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);


/**
 * Socket.io
 */
var io = app.io;
io.listen(server);`

Além disso, fazer com que essa conexão funcione requer a implementação da API do lado do cliente também. Isso não é específico do Express, mas sem ele a chamada de conexão não funcionará. A API está incluída em

/node_modules/socket.io-client/socket.io.js. 

Inclua este arquivo no front end e teste com o seguinte:

var socket = io.connect('http://localhost:3000');
Rickrizzo
fonte
7

Depois de ler todos os comentários, descobri o seguinte usando a versão do servidor Socket.io: 1.5.0

Problemas que encontrei:

  1. var sockIO = require ('socket.io') deve ser var sockIO = require ('socket.io') () . (Crédito para: Zhe Hu )

  2. sockIO.attach deve ser sockIO. ouvir (crédito para: rickrizzo )

Passos

  1. Instale o Socket.io com o seguinte comando:

    npm install --save socket.io
  2. Adicione o seguinte ao app.js :

    var sockIO = require('socket.io')();
    app.sockIO = sockIO;
  3. Em bin / www , após var server = http.createServer (app) , adicione o seguinte:

    var sockIO = app.sockIO;
    sockIO.listen(server);
  4. Para testar a funcionalidade, em app.js , você pode adicionar a linha:

    sockIO.on('connection', function(socket){
        console.log('A client connection occurred!');
    });
Brian
fonte
5

Um tutorial para iniciantes de Cedric Pabst
aqui é um resumo básico do link para um bate-papo de aplicativo:

usando express-generate e o motor ejs utilizável em todo roteamento padrão de arquivo .ejs em express-generate

edite o arquivo bin \ www e adicione este app.io.attach (servidor); como isso

...
/*
 * Create HTTP server.
/*  
var server = http.createServer(app);
/*
 * attach socket.io
/*  
app.io.attach(server); 
/*
 * Listen to provided port, on all network interfaces.
/*  
...

editar em app.js

//connect socket.io
... var app = express();
// call socket.io to the app
app.io = require('socket.io')();

//view engine setup
app.set('views', path.join(_dirname, 'views'));
...



...
//start listen with socket.io
app.io.on('connection', function(socket){
console.log('a user connected');

// receive from client (index.ejs) with socket.on
socket.on('new message', function(msg){
      console.log('new message: ' + msg);
      // send to client (index.ejs) with app.io.emit
      // here it reacts direct after receiving a message from the client
      app.io.emit('chat message' , msg);
      });
});
...
module.exports = app;

editar em index.ejs

 <head>  
   <title><%= title %></title>
   <link rel='stylesheet' href='/stylesheets/style.css' />
   <script src="/socket.io/socket.io.js"></script>
   //include jquery
   <script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
   <script>
   var socket = io();
   //define functions socket.emit sending to server (app.js) and socket.on receiving 
     // 'new message' is for the id of the socket and $('#new-message') is for the button
     function sendFunction() {
     socket.emit('new message', $('#new-message').val());
     $('#new-message').val('');
   }
    // 'chat message' is for the id of the socket and $('#new-area') is for the text area
   socket.on('chat message', function(msg){
     $('#messages-area').append($('<li>').text(msg));
   });
   </script>
 </head>  

 <body>  
   <h1><%= title %></h1>
   <h3>Welcome to <%= title %></h3>
   <ul id="messages-area"></ul>
   <form id="form" onsubmit="return false;">
     <input id="new-message" type="text" /><button onclick="sendFunction()">Send</button>
   </form>
 </body>

Divirta-se :) e muito obrigado a Cedric Pabst

AnnaBanana
fonte
2

Algumas respostas anteriores não estão funcionando e outras são excessivamente complicadas. Em vez disso, tente a seguinte solução ...

Instale os módulos de nó socket.io do lado do servidor e do lado do cliente:

npm install --save socket.io socket.io-client

Lado do servidor

Adicione o seguinte código a bin / www após a definição do servidor var server = http.createServer(app);:

/**
 * Socket.io
 */

var io = require('socket.io')(server);

io.on("connection", function(socket){
  console.log("SOCKET SERVER CONNECTION");
  socket.emit('news', { hello: 'world' });
});

Cliente

Se estiver usando webpack, adicione o seguinte código ao arquivo entry.js do webpack :

var socket = require('socket.io-client')();
socket.on('connect', function(){
  console.log("SOCKET CLIENT CONNECT")
});

socket.on('news', function(data){
  console.log("SOCKET CLIENT NEWS", data)
});

Feito. Visite seu site e verifique o console do desenvolvedor js do navegador.

s2t2
fonte