[英]Why am I getting "Cannot access 'server' before initialization" error in NodeJS?
I am getting the dreaded Cannot access 'server' before initialization
error in code that is identical to code that's running in production.在与生产中运行的代码相同的代码中出现Cannot access 'server' before initialization
。
The only things that have changed are my OS version (macOS 10.11->10.14) my NodeJS version (10->12) and my VSCode launch.json
, but I cannot see anything in either that would cause an issue.唯一改变的是我的操作系统版本(macOS 10.11->10.14)我的 NodeJS 版本(10->12)和我的 VSCode launch.json
,但我看不到任何会导致问题的东西。 My Node version went from 10 to 12, but in production it went from 8 to 15 without issue.我的 Node 版本从 10 到 12,但在生产中它从 8 到 15 没有问题。 I routinely keep launch.json
pretty sparse, and the same error happens using node server
in Terminal.我经常保持launch.json
非常稀疏,并且在终端中使用node server
也会发生同样的错误。
Here is the offending code.这是有问题的代码。 The issue occurs because I have shutdown()
defined before server
and it references server
.出现此问题是因为我在server
之前定义了shutdown()
并且它引用了server
。 It's written to add an event-handler and then cause the event.编写它是为了添加一个事件处理程序,然后引发事件。 Yes, it could be refactored but it already works.是的,它可以被重构,但它已经可以工作了。 It works, really.它确实有效。 In 21 instances spread over 7 servers.在 21 个实例中分布在 7 个服务器上。
I have tried changing the declaraion/init of server
from const
to var
but that does not fix it.我尝试将server
的声明/初始化从const
更改为var
但这并不能解决它。 As mentioned, this is code that's running in prod ?如前所述,这是在 prod 中运行的代码? What's wrong with my environment?我的环境有什么问题?
Maybe a better question is: why did this ever work?也许更好的问题是:为什么这会奏效?
'use strict'
const fs = require('fs');
const https = require('https');
const cyp = require('crypto').constants;
const stoppable = require('./common/stoppable.js');
const hu = require('./common/hostutil');
process.on('uncaughtException', err => {
wslog.error(`Uncaught Exception: ${err} ${err.stack}`);
shutdown();
});
process.on('unhandledRejection', (reason, p) => {
wslog.error(`Unhandled Promise Rejection: ${reason} - ${p}`);
});
// 'shutdown' is a known static string sent from node-windows wrapper.js if the service is stopped
process.on('message', m => {
if (m == 'shutdown') {
wslog.info(`${wsconfig.appName} has received shutdown message`);
shutdown();
}
});
process.on('SIGTERM', shutdown);
process.on('SIGINT', shutdown);
process.on('SIGHUP', shutdown);
function shutdown() {
httpStatus = 503; // Unavailable
wslog.info(`${wsconfig.appName} httpStatus now ${httpStatus} - stopping server...`);
// Error happens on this next line; It should not execute till after server is running already
server.on('close', function () {
wslog.info(`${wsconfig.appName} HTTP server has stopped, now exiting process.`);
process.exit(0)
});
server.stop();
}
// Init and start the web server/listener
var combiCertFile = fs.readFileSync(wsconfig.keyFile, 'utf8');
var certAuthorityFile = fs.readFileSync(wsconfig.caFile, 'utf8');
var serverOptions = {
key: combiCertFile,
cert: combiCertFile,
ca: certAuthorityFile,
passphrase: wsconfig.certPass,
secureOptions: cyp.SSL_OP_NO_TLSv1 | cyp.SSL_OP_NO_TLSv1_1
};
var server = https.createServer(serverOptions, global.app)
.listen(wsconfig.port, function () {
wslog.info(`listening on port ${wsconfig.port}.`);
});
server.on('clientError', (err, socket) => {
if (err.code === 'ECONNRESET' || !socket.writable) { return; }
// ECONNRESET was already logged in socket.on.error. Here, we log others.
wslog.warn(`Client error: ${err} ${err.stack}`);
socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
});
server.on('error', (err)=>{
if ( err.code === 'EADDRINUSE' ) {
wslog.error(`${err.code} FATAL - Another ${wsconfig.appName} or app is using my port! ${wsconfig.port}`);
} else {
wslog.error(`${err.code} FATAL - Server error: ${err.stack}`);
}
shutdown();
})
combiCertFile = null;
certAuthorityFile = null;
// Post-instantiation configuration required (may differ between apps: need an indirect way to plug in app-specific behavior)
stoppable(server, wsconfig.stopTimeout);
// Load all RESTful endpoints
const routes = require('./routes/');
This is a runtime error, which happens only in a very specific situation.这是一个运行时错误,仅在非常特定的情况下才会发生。 But actually this exact error shouldn't happen with var server =...
but only with const server =...
or let server =...
.但实际上这个确切的错误不应该发生在var server =...
上,而只发生在const server =...
或let server =...
上。 With var server =...
the error message should say "Cannot read properties of undefined"
使用var server =...
错误消息应显示"Cannot read properties of undefined"
What happens怎么了
You have an error handler for uncaughtException
which is calling shutdown()
and in shutdown()
you are referencing your server
.您有一个uncaughtException
的错误处理程序,它正在调用shutdown()
并且在shutdown()
中您正在引用您的server
。 But consider what happens if your code throws an exception before you initialized your server
.但是请考虑如果您的代码在初始化server
之前引发异常会发生什么。 For instance if your cert or key cannot be read from the disk, cert or key are invalid... So nothing will be assigned to server
, and an exception will be raised.例如,如果无法从磁盘读取您的证书或密钥,则证书或密钥无效......因此不会将任何内容分配给server
,并且会引发异常。
Then the handler for your uncaught exception will fire and call the shutdown()
function, which then tries to access the server
, which of course hasn't been initialized yet.然后,未捕获异常的处理程序将触发并调用shutdown()
function,然后尝试访问当然尚未初始化的server
。
How to fix怎么修
Check what the unhandled exception is, that is thrown before your server is initialized and fix it.检查未处理的异常是什么,在初始化服务器之前抛出并修复它。 In your production environment, there is probably no exception, because the configuration and environment is properly set up.在您的生产环境中,可能也不例外,因为配置和环境设置正确。 But there is at least one issue in your develepment environment, which causes an exception.但是您的开发环境中至少存在一个问题,这会导致异常。
Difference between var
and const
var
和const
的区别
And the difference between var server =...
and const server =...
is quite a subtle one. var server =...
和const server =...
之间的区别非常微妙。 For both, the declaration of the variable is hoisted up to the top of their respective scope.对于两者,变量的声明都被提升到它们各自的 scope 的顶部。 In your case it's always global, also for const
.在您的情况下,它始终是全局的,对于const
也是如此。 But variables declared as var
are assigned a value of undefined
whereas variables declared as let/const
are not initialized at all.但是声明为var
的变量被赋值为undefined
,而声明为let/const
的变量根本没有被初始化。
You can easily reproduce this error if you uncomment either error1
or error2
in the following code.如果您在以下代码中取消注释error1
或error2
,您可以轻松地重现此错误。 But error3
alone won't produce this ReferenceError
because bar
will already be initialized.但是单独的error3
不会产生这个ReferenceError
因为bar
已经被初始化了。 You can also replace const bar =
with var bar =
and you will see, that you get a different error message.您也可以将const bar =
替换为var bar =
,您会看到,您会收到不同的错误消息。
process.on("uncaughtException", err => {
console.log("uncaught exception");
console.log(err);
foo();
});
function foo() {
console.log("foo");
console.log(bar.name);
}
function init() {
// throw new Error("error1");
return { name: "foobar"}
}
// throw new Error("error2");
const bar = init();
//throw new Error("error3");
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.