使用Go开发收据Web应用时JSON解析失败的技术求助
解决Go Web应用中JSON解析错误:invalid character 'r' looking for beginning of value
问题根源
你遇到的错误是因为前端表单默认提交的是application/x-www-form-urlencoded格式,请求体内容是类似receipt={你的JSON内容}的键值对,而非纯JSON字符串。后端用json.NewDecoder(r.Body).Decode(&receipt)直接解析整个请求体,自然会因为开头的receipt=字符导致JSON解析失败。
修复方案
提供两种可行的修复方式,根据你的需求选择:
方案1:后端适配表单提交(无需修改前端)
修改receiptHandler中的POST处理逻辑,先解析表单数据,提取出textarea中的JSON字符串后再进行解析:
func receiptHandler(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { // 解析表单数据 err := r.ParseForm() if err != nil { http.Error(w, "表单解析失败", http.StatusBadRequest) return } // 获取输入的JSON内容 receiptJSON := r.FormValue("receipt") if receiptJSON == "" { http.Error(w, "请输入收据JSON", http.StatusBadRequest) return } var receipt Receipt // 将JSON字符串解析到结构体 err = json.Unmarshal([]byte(receiptJSON), &receipt) if err != nil { http.Error(w, "JSON格式错误:"+err.Error(), http.StatusBadRequest) return } j, _ := json.MarshalIndent(receipt, "", " ") fmt.Println(string(j)) result := processReceipt(receipt) tmpl := template.Must(template.ParseFiles("result.html")) tmpl.Execute(w, result) } else { tmpl := template.Must(template.ParseFiles("index.html")) tmpl.Execute(w, nil) } }
方案2:前端改为提交纯JSON(RESTful风格)
保留后端原有的JSON解析逻辑,修改前端用JavaScript发送JSON格式请求:
<!DOCTYPE html> <html> <head> <title>Receipt Processor</title> </head> <body> <h1>Receipt Processor</h1> <textarea id="receipt" rows="10" cols="50"></textarea><br><br> <button onclick="submitReceipt()">Process Receipt</button> <script> function submitReceipt() { const receiptJSON = document.getElementById('receipt').value; fetch('/', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: receiptJSON, }) .then(response => { if (!response.ok) throw new Error('请求失败'); return response.text(); }) .then(html => { document.body.innerHTML = html; }) .catch(error => { alert('错误:' + error.message); }); } </script> </body> </html>
这种方式下,后端原有的json.NewDecoder代码可以正常工作,无需修改。
额外优化建议
- 错误提示优化:解析JSON时可以返回更友好的错误信息,帮助用户定位格式问题
- 随机ID生成优化:当前用
rand.Intn生成ID,建议替换为crypto/rand包生成更安全、不易重复的随机ID - 字段类型优化:
Total和Price字段可以改用decimal.Decimal(第三方库)或float64存储,减少字符串转浮点数的重复操作,避免精度丢失
内容的提问来源于stack exchange,提问作者cad545
相关产品推荐
相关产品推荐

