当我用express-generator生成一个Web服务器时,我得到了这个文件夹结构:
[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 ...
答案实际上取决于您的生态系统。如果您知道应用程序将使用的所有服务,那么您可以尝试在ExpressJS中间件函数中检查它们,该函数在路由代码之前被调用。您可以使用一组Promise来跟踪服务准备情况,并使用一个布尔值来告知所有服务是否准备就绪。如果所有服务都准备就绪,则中间件功能可以调用next()
,但如果没有,则您可能会返回一个HTML页面,告诉用户该站点正在进行维护或未准备就绪,他们应稍后再试。我可以看到您将所有这些承诺封装在一个中间件函数中,该函数管理它们是否准备就绪,以免使您的app.js或bin / www文件混乱。
考虑一个简单的express api,该api在端口3000上返回'OK'。