Fetch发送PATCH请求后端接收数据为null问题排查(Postman正常)
PATCH请求拿不到请求体的修复方案
你的后端接口在Postman中可正常运行,说明接口本身和数据库逻辑没有问题,故障全部出在前端请求代码中,核心问题共3个:
- 致命拼写错误:fetch的请求头配置字段名应为复数
headers,你写成了单数header,导致设置的Content-Type: application/json完全没有生效。后端无法识别请求体为JSON格式,自然解析不到task字段,拿到null/空值。 - 弹窗输入判断逻辑bug:当用户点击prompt弹窗的「取消」按钮时,返回值是
null,此时直接访问alert.length会抛出JS类型错误,中断请求执行;同时没有对输入的前后空格做过滤,容易提交无效内容。 - 请求路径隐患:使用相对路径
api/todos/xxx时,会基于当前页面路由拼接请求地址,若当前页面不在站点根路径,会直接请求到错误的接口地址。
修复后的前端代码
import React from "react"; class UpdateBtn extends React.Component { // 将请求方法抽到render外,避免每次渲染重复创建函数 updateTodo = (todoId, newTask) => { // 路径补全前缀斜杠,修正headers为复数形式 fetch(`/api/todos/${todoId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ task: newTask }) }) .then(res => res.json()) .then(() => { // 等请求成功后再刷新页面,避免请求没发出去就刷新 window.location.reload() }) .catch(error => console.error(error.message)) } handleUpdate = (e) => { const newTask = window.prompt("Update Task:") // 覆盖所有无效输入场景:点取消返回null、输入空串、输入全空格 if (!newTask || !newTask.trim()) { return; } this.updateTodo(e.target.id, newTask.trim()) } render() { return ( <button className="updateBtn" id={this.props.id} value={this.props.value} onClick={this.handleUpdate} > Update </button> ) } } export default UpdateBtn;
后端可选优化(提升稳定性)
你当前的后端代码缺少参数校验和错误状态返回,可以补充以下逻辑减少异常:
// 确保已注册JSON解析中间件(Postman能跑通说明已配置,可忽略) // app.use(express.json()) app.patch('/api/todos/:id', async (req, res) => { try { const { task } = req.body; // 拦截空任务值,避免写入脏数据 if (!task || !task.trim()) { return res.status(400).json({ error: "任务内容不能为空" }) } // 加上RETURNING *可以直接拿到更新后的记录,不需要返回原始请求体 const updateResult = await pool.query( "UPDATE todolist SET task = $1 WHERE id = $2 RETURNING *;", [task.trim(), req.params.id] ) res.json(updateResult.rows[0]) } catch (error) { console.error(error.message) res.status(500).json({ error: "服务更新失败" }) } })
内容的提问来源于stack exchange,提问作者Wayne Odell
相关产品推荐
相关产品推荐

