[Fixed] Why do I need to explicitly call app.listen(port) in order to make express-ws working?

Issue

I’m new to NodeJS Express, I was following the official tutorial from express-ws to setup websocket in the simple project generated by npx express-generator . In the app.js, I’ve to explicitly call the app.listen(3000) in order to make the ws connection working. Am I doing this correctly although it is working ? What’s the difference between app.listen vs. server.listen in this case? what is app.set(port,port) in www.js used for?

app.js – I’ve to add the last line below:

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

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

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

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

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));


app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;
app.listen(3001)// for websocket listen port

www.js – this file was generated by the express-generator and I see it’s already calling app.set('port',port) and server.listen(port)

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('xapp:server');
var http = require('http');

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);



/**
 * 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);

/**
 * Normalize a port into a number, string, or false.
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  var bind = typeof port === 'string'
    ? 'Pipe ' + port
    : 'Port ' + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case 'EACCES':
      console.error(bind + ' requires elevated privileges');
      process.exit(1);
      break;
    case 'EADDRINUSE':
      console.error(bind + ' is already in use');
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === 'string'
    ? 'pipe ' + addr
    : 'port ' + addr.port;
  debug('Listening on ' + bind);
}

Solution

The .listen(port) method on either a server object or on the Express app object is what actually starts your server so that it is listening for incoming requests. Without that, you don’t have a running http server. And, you need a running http server for both Express and for your webSocket. If you don’t call something that triggers server.listen(), then you won’t have a running server. It will be all configured and waiting to start, but won’t yet be running.

If you look at the code for app.listen(), it is just a helper function. All, it does is this:

app.listen = function listen() {
  var server = http.createServer(this);
  return server.listen.apply(server, arguments);
};

It creates an http server object and then calls .listen() on it. It’s just a shortcut. If you have a reason to want to create your own http server object and then call server.listen() on that one, you can do it that way too. In fact, if you’re starting an https server, you have to do it that way because you have to pass the right arguments to https.createServer() which app.listen() doesn’t do for you.

Leave a Reply

(*) Required, Your email will not be published