正常启动Node.js Web服务器应用程序的好方法是什么

问题描述 投票:2回答:2

当我用express-generator生成一个Web服务器时,我得到了这个文件夹结构:

  • bin / www
  • 意见/ ...
  • app.js
  • package.json
  • ...

[bin/www这样叫app.js

var app = require('../app');
// ...
var server = http.createServer(app);
server.listen(port);

app.js像这样创建应用程序:

var express = require('express')
var mongoose = require('mongoose')

mongoose.connect(process.env.DATABASE_URL).then(
    () => {
      debug('Database is connected')
    },
    err => {
      debug('An error has occured with the database connection')
      process.exit(1)
    }
  )

var app = express()

// Midllewares
app.use(/* some middleware 1 */)
app.use(/* some middleware 2 */)
app.use(/* some middleware 3 */)
app.use(/* some middleware ... */)

// Routes
app.get('/', function(req, res, next) {
  res.json({'message': 'Welcome to my website'})
})
app.get('/users', function(req, res, next) {
  Users.find({}).exec(function(err, users) {
    if (err) {
      res.json({'message': 'An error occured'})
      return
    }
    res.json('users': users)
  })
})
// ... others routes ...

module.exports = app

确定,这是express-generator的Web服务器样板。但是,如果我想以一种好的方式启动我的应用程序,则在我的应用程序准备就绪时,我必须调用process.send('ready')。 (“就绪”表示所有服务均已准备就绪,可以使用:数据库,redis,调度程序...)(当您的应用程序准备就绪时,请致电process.send('ready')是了解您的Web服务器应用程序已准备就绪的最佳实践。可以使用此信号通过流程管理或其他系统)

问题在于,在bin/www中启动了应用程序(调用了server.listen()),而不必保证已建立数据库连接。换句话说,如果没有保证,Web服务器应用程序已准备好监听流量。

我读到在bin/www中启动服务器是最佳做法

上面的示例还不完整,我们可以认为我们有一个带有多个服务的应用程序,必须在接受请求之前启动这些服务(服务示例:redis,作业调度程序,数据库连接,与其他服务器的ftp连接...)

我已经检查了一些Node.js应用程序的流行和高级样板:

但是在调用server.listen(port)之前,它们都不照顾应用程序的就绪状态,这使Web服务器开始侦听传入的请求。这让我感到非常惊讶,我不明白为什么

具有多个服务的Web服务器应用程序的代码示例,在接受传入请求之前,我们必须等待这些服务:

bin/www

var app = require('../app');
// ...
var server = http.createServer(app);
server.listen(port);

app.js

var express = require('express')
var mongoose = require('mongoose')

// **************
// Service 1 : database
mongoose.connect(process.env.DATABASE_URL).then(
  () => {
    debug('Database is connected')
  },
  err => {
    debug('An error has occured with the database connection')
    process.exit(1)
  }
)
// **************

// **************
// Service 2
// Simulate a service that take 10 seconds to initialized
var myWeatherService = null
setTimeout(function() {
  myWeatherService.getWeatherForTown = function(town, callback) {
    weather = 'sun'
    callback(null, weather)
  }
}, 10*1000)
// **************

// **************
// Other services...
// **************

var app = express()

// Midllewares
app.use(/* some middleware 1 */)
app.use(/* some middleware 2 */)
app.use(/* some middleware 3 */)
app.use(/* some middleware ... */)

// Routes
app.get('/', function(req, res, next) {
  res.json({'message': 'Welcome to my website'})
})
app.get('/users', function(req, res, next) {
  Users.find({}).exec(function(err, users) {
    if (err) {
      res.json({'message': 'An error occured'})
      return
    }
    res.json({'users': users})
  })
})
app.get('/getParisWeather', function(req, res, next) {
  Users.getWeatherForTown('Paris', function(err, weather) {
    if (err) {
      res.json({'message': 'An error occured'})
      return
    }
    res.json({'town': 'Paris', weatcher: weather})
  })
})
// ... others routes ...

module.exports = app

如果启动我的应用程序,然后在初始化localhost:port/getParisWeather之前调用myWeatherService,则会收到错误消息

我已经在考虑解决方案:将每个服务声明移到bin / www中,仅将与express app声明有关的代码放到app.js中。

bin/www

var app = require('../app');
var mongoose = require('mongoose')
var server = null;

Promise.resolve()
.then(function () {
  return new Promise(function (resolve, reject) {
    // start service 1
    console.log('Service 1 is ready')
    resolve()
  })
})
.then(function () {
  return new Promise(function (resolve, reject) {
    // start service 2
    console.log('Service 2 is ready')
    resolve()
  })
})
.then(function () {
  return new Promise(function (resolve, reject) {
    // start other services...
    console.log('Others services is ready')
    resolve()
  })
})
.then(function () {
  return new Promise(function (resolve, reject) {
    server = http.createServer(app);
    server.listen(port);
    console.log('Server start listenning')
  })
})
.then(function () {
  next()
})
.catch(next)
.finally(function () {

})
.done()

app.js

var express = require('express')
var app = express()

// Midllewares
app.use(/* some middleware 1 */)
app.use(/* some middleware 2 */)
app.use(/* some middleware 3 */)
app.use(/* some middleware ... */)

// Routes
app.get('/', function(req, res, next) {
  res.json({'message': 'Welcome to my website'})
})
app.get('/users', function(req, res, next) {
  Users.find({}).exec(function(err, users) {
    if (err) {
      res.json({'message': 'An error occured'})
      return
    }
    res.json({'users': users})
  })
})
app.get('/getParisWeather', function(req, res, next) {
  Users.getWeatherForTown('Paris', function(err, weather) {
    if (err) {
      res.json({'message': 'An error occured'})
      return
    }
    res.json({'town': 'Paris', weatcher: weather})
  })
})
// ... others routes ...

module.exports = app

但是我知道将逻辑放在bin / www中不是一个好习惯,它只能包含服务器的起始行...

所以,我的问题是,我们如何启动网络服务器应用程序以遵守最佳做法//

最佳做法是什么?

我知道我只能将所有内容放在一个文件中,然后在该文件的末尾启动Web服务器,这不是我的问题。我要问的是如何以良好的方式和最佳做法进行操作]

[当我使用express-generator生成Web服务器时,我得到以下文件夹结构:bin / www views / ... app.js package.json ... bin / www call app.js像这样:var app = require( '../app'); // ... var ...

node.js express
2个回答
0
投票

答案实际上取决于您的生态系统。如果您知道应用程序将使用的所有服务,那么您可以尝试在ExpressJS中间件函数中检查它们,该函数在路由代码之前被调用。您可以使用一组Promise来跟踪服务准备情况,并使用一个布尔值来告知所有服务是否准备就绪。如果所有服务都准备就绪,则中间件功能可以调用next(),但如果没有,则您可能会返回一个HTML页面,告诉用户该站点正在进行维护或未准备就绪,他们应稍后再试。我可以看到您将所有这些承诺封装在一个中间件函数中,该函数管理它们是否准备就绪,以免使您的app.js或bin / www文件混乱。


0
投票

考虑一个简单的express api,该api在端口3000上返回'OK'。

© www.soinside.com 2019 - 2024. All rights reserved.