【发布时间】:2021-08-21 10:48:09
【问题描述】:
我正在尝试为我的 Node.js 服务器实现 JSON 日志;但是,当我快速发送请求时,JSON.parse() 会抛出错误。我认为这可能是由于对我的日志文件的并发读写造成的,因为fs 方法是异步的。
我收到的错误之一是:
SyntaxError: Unexpected end of JSON input
这将通过降低请求速率来解决。
但是,在其他时候,JSON 本身会出现语法错误,并且在我删除它们并重新启动服务器之前无法解析日志:
SyntaxError: Unexpected token [TOKEN] in JSON at position [POSITION]
有时日志的结尾看起来像这样,以一个额外的]结尾:
[
...,
{
"ip": ...,
"url": ...,
"ua": ...
}
]]
或者这个:
[
...,
{
"ip": ...,
"url": ...,
"ua": ...
}
]
]
这是我的服务器的一个非常简化的版本:
"use strict"
const fsp = require("fs").promises
const http = require("http")
const appendJson = async (loc, content) => {
const data = JSON.parse(
await fsp.readFile(loc, "utf-8").catch(err => "[]")
)
data.push(content)
fsp.writeFile(loc, JSON.stringify(data))
}
const logReq = async (req, res) => {
appendJson(__dirname + "/log.json", {
ip: req.socket.remoteAddress,
url: req.method + " http://" + req.headers.host + req.url,
ua: "User-Agent: " + req.headers["user-agent"],
})
}
const html = `<head><link rel="stylesheet" href="/main.css"></head><script src="/main.js"></script>`
const respond = async (req, res) => {
res.writeHead(200, { "Content-Type": "text/html" }).end(html)
logReq(req, res)
}
http.createServer(respond).listen(8080)
我测试了通过快速刷新页面或在浏览器控制台中打开许多选项卡在 Firefox 和 Chromium 中发送大量请求(但由于某种原因,使用 cURL 发送数千个请求都不会导致错误):
for (let i = 0; i < 200; i++)
window.open("http://localhost:8080")
通常,如果完整的 HTML 页面自己发出更多请求,那么会导致这些错误的请求要少得多。
这些错误的原因是什么,我该如何解决它们,尤其是第二个?
【问题讨论】:
-
我相信你可以简单地
await fsp.writeFile(...)。你不是在等待它,我有直觉它可能会解决问题