POST新增用户后PUT请求误删新用户问题求助
Node.js用户注册后PUT修改数据导致新用户被删除的问题
POST请求注册新用户时,数据能正常写入users.json,但后续发起PUT请求修改该用户数据时,刚新增的用户会被删除。已注意到注册后JSON文件变成一行,但不认为是问题,猜测PUT请求可能读取了旧的用户列表,寻求解决办法。
相关代码
前端PUT请求代码
//Changing user Data export async function changeData(id, body) { try { await axios.put(`http://localhost:8000/users/${id}`, body, { headers: { 'Content-Type': 'application/json', 'Authorization': localStorage.getItem('auth._token.local') } }); return true; } catch (e) { return false; } }
后端注册新用户的POST接口代码
// Register New User server.post('/register', (req, res) => { console.log("register with request body", req.body) const {username, password, firstname, lastname, roles} = req.body if(!username || !password || !firstname || !lastname || !roles) { const status = 400 const message = "Bad Request, make sure all properties are set in request body" res.status(status).json({status, message}) return } if (req.headers.authorization === undefined || req.headers.authorization.split(' ')[0] !== 'Bearer') { const status = 401 const message = 'Error in authorization format' res.status(status).json({status, message}) return } // Send only token part to admin check if(!isAdmin(req.headers.authorization.split(' ')[1])) { const status = 401 const message = 'Only permitted by admin' res.status(status).json({status, message}) return } if(isAuthenticated({username, password}) === true) { const status = 401 const message = 'Email and Password already exist' res.status(status).json({status, message}) return } fs.readFile("./users.json", (err, file) => { if (err) { const status = 401 const message = err res.status(status).json({status, message}) return } // Get current users data const data = JSON.parse(file.toString()) // Get the id of last user const last_item_id = data.users[data.users.length - 1].id //Add new user data.users.push({id: last_item_id + 1, username: username, password: password, firstname: firstname, lastname: lastname, roles: roles}) //add some data const writeData = fs.writeFile("./users.json", JSON.stringify(data), (err, result) => { // WRITE if (err) { const status = 401 const message = err res.status(status).json({status, message}) } else { // 文件写入成功后再返回响应 res.status(201).json({status: 201, message: "Successfully created"}) } }) }) // 原代码这里直接返回响应,此时文件可能还未写入完成 // res.status(201).json({status: 201, message: "Successfully created"}) })
后端处理用户数据修改的中间件代码
// handle changing user data server.use((req, res, next) => { console.log('Entering Users') if(req.method === 'PUT' && req.url.includes("/users")) { if(req.body) { const decodedToken = jwt.decode(req.headers.authorization.split(' ')[1]) const userList = JSON.parse(fs.readFileSync('./users.json', 'UTF-8')) const userinfo = userList.users.find((user) => user.id === decodedToken.id) if(!req.body.password) { req.body.password = userinfo.password } // if admin made the request, he should be able to change roles if(req.body.roles && decodedToken.roles && decodedToken.roles.includes("admin")) { console.log("Able to change"); next() return } req.body.roles = decodedToken.roles } else { res.status(400).json( { status: 400, message: "Bad request, make sure all properties are set in request body" } ) return } } next() })
问题原因与解决方案
核心问题
注册接口中,fs.writeFile是异步操作,但原代码在调用fs.writeFile后立即返回了201响应。此时文件可能还未完成写入,客户端收到成功响应后立刻发起PUT请求,中间件通过fs.readFileSync读取的仍是旧的文件内容(新用户尚未写入)。后续PUT路由处理时,会基于旧列表修改并写入文件,导致刚注册的用户被覆盖删除。
修复步骤
调整注册接口的响应时机:将返回201响应的代码移到
fs.writeFile的成功回调中,确保文件写入完成后再通知客户端。修改后的代码已在上面的POST接口中标记。建议使用Promise版fs API:改用
fs.promises.readFile和fs.promises.writeFile,配合async/await语法,避免回调嵌套,代码更易维护:
// 改写后的注册接口(async/await版本) server.post('/register', async (req, res) => { console.log("register with request body", req.body) const {username, password, firstname, lastname, roles} = req.body // 省略前面的校验逻辑... try { const file = await fs.promises.readFile("./users.json"); const data = JSON.parse(file.toString()); const last_item_id = data.users[data.users.length - 1].id; data.users.push({id: last_item_id + 1, username, password, firstname, lastname, roles}); await fs.promises.writeFile("./users.json", JSON.stringify(data)); res.status(201).json({status: 201, message: "Successfully created"}); } catch (err) { res.status(401).json({status: 401, message: err}); } })
- 检查PUT路由逻辑:确保PUT路由在修改用户时,是找到对应ID的用户并更新其属性,而非错误地替换整个用户数组。示例逻辑如下:
server.put('/users/:id', async (req, res) => { const userId = parseInt(req.params.id); try { const file = await fs.promises.readFile("./users.json"); const data = JSON.parse(file.toString()); const userIndex = data.users.findIndex(user => user.id === userId); if (userIndex === -1) { return res.status(404).json({status:404, message: "User not found"}); } // 合并请求体和原有用户数据,保留未修改的字段 data.users[userIndex] = {...data.users[userIndex], ...req.body}; await fs.promises.writeFile("./users.json", JSON.stringify(data)); res.status(200).json({status:200, message: "User updated successfully"}); } catch (err) { res.status(500).json({status:500, message: err}); } })
内容的提问来源于stack exchange,提问作者Chopper
相关产品推荐
相关产品推荐

