为了 self 完善,我正在尝试编写一个纯node.js Web服务器。这个想法是完全避免使用预先编写的中间件或任何非默认的 Node.js 模块来加载静态 HTML、CSS 和 JavaScript,并强制自己学习以纯粹的 Node.js 方式执行此操作的所有来龙去脉。 .
我已经启动并运行了它,并测试了几次,它似乎工作得很好,直到我决定通过在静态页面上快速刷新几次来对其进行压力测试。
前 3-4 次重新加载工作正常。此后,静态 HTML 文件调用的 CSS 或 JavaScript 文件都不会加载。
这是我的文件读取代码:
fs.readFile(filename, function(err, contents) {
if(err) {
throw err;
} else {
res.setHeader("Content-Length", contents.length);
res.setHeader("Content-Type", validExtensions[ext]);
res.statusCode = 200;
res.write(contents);
res.end();
}
});
(validExtensions
只是配对扩展及其相应 mime 类型的数组。)
当页面加载时存在 HTML 文件、CSS 文件和 JavaScript 文件时,此函数将被调用 3 次。再说一次,它工作得很好,直到突然不行了。然后,如果我再次刷新,一切都会恢复正常。
我怀疑发生的情况是有时它会在 CSS 或 JavaScript 文件完成之前完成 HTML 文件。
我能想到的唯一解决方法非常糟糕。我可以创建一个单独的函数来处理所有非 HTML 文件,并让该进程保留剩余文件的计数。然后我可以在处理 HTML 的函数中使用 while 循环,并阻止它执行 res.end() 直到计数为零,但这听起来既难看又可能资源耗尽。
或者我可以使用同步加载所有非 HTML 文件的(更糟糕的)解决方法,但由于该调用将来自其他异步处理函数,所以我真的不想这样做。
如果我只是想构建一个静态站点,我会使用 http-server 或 express 或用于提供静态文件的众多优秀解决方案之一,但它们都具有广泛的模块依赖性,并且我正在尝试无需他们即可完成此任务。
有没有一种优雅而纯粹的方法来确保在所有非 HTML 文件完成其操作之前,加载的 HTML 不会发生 res.end()
?
编辑:所以任何人都可以看到整个上下文、整个项目及其内容,都在 github 上:https://github.com/GoodDamon/customserver
最佳答案
您的问题在于 customServer.url
。如果您打开浏览器的开发工具并检查 app.css
的内容,您会发现偶尔只填充以下行:
console.log("CustomServer 成功加载!");
...这恰好与您的 app.js
文件的内容相同。巧合?没有。如果您查看 Node 控制台输出,您有时会看到以下内容:
10/11/2015 5:42:09 PM: New client request: /css/app.css - Method: GET
10/11/2015 5:42:09 PM: Client requested a file. Testing extension validity...
10/11/2015 5:42:09 PM: File extension .css is VALID. Testing availability...
10/11/2015 5:42:09 PM: New client request: /js/app.js - Method: GET
10/11/2015 5:42:09 PM: Client requested a file. Testing extension validity...
10/11/2015 5:42:09 PM: File extension .js is VALID. Testing availability...
10/11/2015 5:42:09 PM: File is AVAILABLE. Providing to client.
10/11/2015 5:42:09 PM: File is AVAILABLE. Providing to client.
如您所见,浏览器首先请求 app.css
,紧接着请求 app.js
>。因为“提供给客户端”这两行都位于底部,所以您知道您的 Node 服务器尚未处理第一个请求。客户端最终收到的是 app.js
两次,以 .css 和 .js 文件形式发送。
这是为什么呢?理论上,到达 Node 服务器的每个客户端请求都应该与其自己的事件循环隔离。不应有交叉污染。问题在于 customServer.url
,这是您将传入的 req.url
值分配给的内容。因为它位于两个客户端请求的范围之外,所以每个请求都会覆盖前一个请求的值。
这对于同步编程来说不是问题,但 Node.js 是完全异步的,并且会在收到请求后尽快执行所有请求,无论是否还有任何请求仍在等待处理。您的 fs.stat()
调用需要一些时间来执行,并且很有可能在执行成功/错误回调之前另一个请求已经到达服务器。
tl;dr: 此行 - customServer.getFile(customServer.url, res, ext);
将同一文件发送到 2 个不同的请求,因为您正在覆盖 customServer.url
与每个新请求。 在请求范围内跟踪您的请求 URL!
关于javascript - 自定义 Node.js Web 服务器未完成加载 CSS 和 JavaScript,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33070553/