React fetch提交表单空值到Go后端 重复提交问题排查
问题根因
- JS提交时后端接收到全空字段:前端
handleSubmit里发POST请求时设置的Content-Type是application/json,请求体是JSON格式,但Go后端默认调用的ParseForm()只能解析application/x-www-form-urlencoded或multipart/form-data格式的表单数据,不会自动解析JSON请求体,自然读不到任何字段值。原生form提交默认使用application/x-www-form-urlencoded格式,刚好匹配Go默认的表单解析逻辑,所以这种写法能拿到正确值。 - 原生form写法触发两次请求:你修改form属性时大概率没有完全移除
onSubmit事件绑定,导致两套提交逻辑同时生效:第一次是handleSubmit里的fetch发送的请求,此时要么是state字段未正确更新、要么是异步请求被后续的页面跳转中断,后端收到空值;第二次是浏览器触发的原生表单提交,直接读取表单内输入控件的value发送,所以携带的字段值正确。 - 代码里还有两个隐藏bug:
handleSubmit中fetch是异步操作,你没有等待请求完成就直接调用handleHome()触发路由跳转,很容易导致请求还未完全发送就被页面卸载中断,后端收不到完整数据。useEffect里的setMedia(...media, data)写法错误,setMedia接收的第一个参数是新状态值,展开数组直接传参会把数组元素拆成多个独立参数,只有第一个元素会被识别为新状态,正确写法应该是setMedia([...media, data])。
修复方案
方案1:保留React异步提交逻辑(推荐,符合单页应用交互逻辑)
- 修改Go后端代码,增加JSON请求体解析逻辑,不要仅依赖默认的表单解析:
// 定义接收参数的结构体,给字段加json标签 type LinkCreateReq struct { URL string `json:"url"` Headline string `json:"headline"` Description string `json:"description"` Type string `json:"type"` Duration string `json:"duration"` Address string `json:"address"` } // 接口处理逻辑中 var req LinkCreateReq // 解析JSON格式的请求体 err := json.NewDecoder(r.Body).Decode(&req) if err != nil { w.WriteHeader(http.StatusBadRequest) return } // 后续用req里的字段做业务处理即可
- 修改前端
handleSubmit逻辑,等待请求完成后再执行页面跳转,同时确保form标签上没有残留method/action原生属性:
const handleSubmit = async (e) => { e.preventDefault() // 等待接口请求完成再跳转 await fetch("/createLink", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ url: url, headline: headline, description: description, type: type, duration: duration, address: address, }), }) handleHome() }
- 给两个select下拉框设置初始值,避免用户未手动选择时传null:可以把
useState中type的初始值从null改为"article",duration的初始值改为"15",和下拉框默认选中的option匹配。
方案2:使用原生表单提交(不推荐,会触发页面刷新,丢失单页应用体验)
- 完全移除form标签上的
onSubmit={handleSubmit}绑定,删除自定义的handleSubmit提交逻辑,从根源避免重复触发请求。 - 给非必填的输入项设置默认值,避免空值提交:比如地址输入框可以加默认空值,两个select下拉框设置默认选中项,和表单提交的初始值对齐。
内容的提问来源于stack exchange,提问作者Bridget Walsh
相关产品推荐
相关产品推荐

