Express Generator - TypeError: app.set не является функцией

Сначала я сам создал API с Node/Express, чтобы научиться "наивному" пути, как это делает большинство программистов. Это работало хорошо, и я решил попробовать экспресс-генератор.

После настройки все приложение работает нормально.

Я добавил свою кучу кода (в основном в app.js и импортировал несколько маршрутов, чтобы попробовать), я ничего не изменил в bin/www, где настроен express.

Но при запуске я получил эту ошибку, указывающую на этот файл bin/www:

app.set('port', port);
    ^

TypeError: app.set is not a function

Я не знаю, почему эта часть кода, сгенерированная автоматически, не хотела работать сейчас.

Здесь 2 основных файла

bin/www: (генерируется нетронутым)

#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('API: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);
}

app.js:

// Module dependencies
const express = require('express');
const cluster = require('express-cluster'); // fork the service on different thread
const helmet = require('helmet'); // Secure HTTP header
const cors = require('cors');
const path = require('path');
const bodyParser = require('body-parser'); // Help to easily parse the body of req/res
const port = process.env.PORT || 3000;
const mongoose = require('mongoose'); // Manage MongoDB request

cluster(function(worker) {
  var app = express();

  // MongoDB config
  const config = require('./misc/config/index'); // Config variable like MongoDB credential
  mongoose.Promise = global.Promise;
  mongoose.connect(config.getDBConnectionString()); // Config to cnx to mongodb
  // mongoose.connect(config.getDBConnectionString(), { config: { autoIndex: false } });

  // Middleware
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({extended: true}));
  app.use(helmet.frameguard()); // Default Value - Help to secure request by putting some setting in the header
  app.use(cors()); // Handling Cross Origin Ressource Sharing

  // Logfile
  const log = require('./misc/log/log');
  app.use(log);

  // Config Landingpage to /
  app.use('/assets', express.static(path.join(__dirname, 'public')));
  app.set('view engine', 'ejs');

  // Entry point
  const entryPoint = require('./routes/entryPoint');
  app.get('/', entryPoint.index);
  app.get('/api', function (req, res) {
    res.redirect(301, '/');
  })

  // API Key handler
  const auth = require('./misc/auth/auth');
  app.use(auth);

  // List
  const list = require('./routes/list/listRouter'); // Get List endpoints
  // app.use('/api/list', list);

  // Map
  const map = require('./routes/map/mapRouter'); // Get List endpoints
  // app.use('/api/map', map);

  module.exports = app;
}, {count: 2})

Я экспортирую приложение, которое включает в себя экспресс (). Так что здесь я что-то упускаю, но я не вижу, что.

1 ответ

Решение

Проблема вызвана этой настройкой:

cluster(function(worker) {
  var app = express();
  ...
  module.exports = app;
}, { ... });

Так как cluster вызовет "рабочую функцию" асинхронно, экспорт также выполняется асинхронно, что слишком поздно для bin/www, Кроме того, рабочая функция будет выполняться в отдельном процессе, что также усложняет ситуацию.

Так как bin/www относительно просто с точки зрения того, что он делает, вы можете выбрать перемещение его содержимого (или, по крайней мере, суть того, что он делает) в app.js и запустите свое приложение с node app.js, Вы могли бы даже заменить bin/www с помощью простого скрипта:

#!/usr/bin/env node 

require('../app');

Кроме того, вы можете оставить свой код как есть и положиться на внешнюю программу, чтобы обеспечить балансировку нагрузки между доступными процессорами. Популярным решением для этого является pm2, хотя это не работает хорошо для всех (кажется, хитом и промахом).

Если вам нужно передать переменные окружения, вы можете сделать это из командной строки:

$ env API_KEY=XXX pm2 start app.js

Или создайте файл конфигурации для вашего приложения.

Там также есть пакет под названием dotenv это позволит вашему приложению Node напрямую читать переменные окружения из файла.

Другие вопросы по тегам