JS客户端向Golang服务器POST数据失败,请求排查问题原因
客户端POST请求返回无效请求的问题分析
问题场景
搭建了一套以JS/HTML为客户端、Golang为服务端、PostgreSQL为数据库的REST API授权服务:
- Postman发送POST请求时,能正常获得预期响应,数据也能存入数据库
- JS/HTML客户端发送请求时,返回结果为无效请求:
{"message":"Invalid request","status":false}
服务端核心代码
var CreateAccount = func(w http.ResponseWriter, r *http.Request) { account := &models.Account{} err := json.NewDecoder(r.Body).Decode(account) // 解析请求体为结构体,出错则返回无效请求 if err != nil { utils.Respond(w, utils.Message(false, "Invalid request")) return } resp := account.Create() // 创建账户 utils.Respond(w, resp) }
客户端代码
JavaScript部分
'use strict' const form = document.getElementById('form'); const url = "http://localhost:8080/api/user/login"; const myHeaders = new Headers(); myHeaders.append("Content-Type", "application/json"); form.addEventListener('submit', (e) => { e.preventDefault(); const data = new FormData(form); let preparedData = JSON.stringify([...data].flat()); console.log(preparedData) fetch(url, { method: "POST", body: data, }) .then(response => response.text()) .then(result => console.log(result)) .catch(error => console.log('error', error)); });
HTML部分
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel='stylesheet' href='style.css'> <title>Real Estate Moskow Hack</title> </head> <body> <header class="header"> </header> <!-- HEADER END --> <main class="main"> <form action="http://localhost:8080/api/user/login" method="POST" id="form"> <input class="email" type="text" name="email" placeholder="Введите email"> <input class="password" type="password" name="password" id="password" placeholder="Введите пароль"> <button class="button" type="submit">send data</button> </form> </main> <!-- MAIN END --> <footer class="footer"> </footer> <script src="script.js"></script> </body> </html>
问题定位与原因
问题出在客户端,核心原因有两点:
未传递正确的请求头
服务端依赖json.NewDecoder解析JSON格式请求体,需要请求头包含Content-Type: application/json。客户端虽然创建了myHeaders配置该头,但没有在fetch请求中传入这个配置项,导致请求头默认是multipart/form-data,服务端无法解析。请求体格式不匹配
客户端实际发送的是FormData对象,而非服务端期望的JSON格式。即便定义了preparedData做JSON序列化,但最终fetch的body参数传的是原始data(FormData),而且[...data].flat()的转换方式会把表单的键值对转为扁平数组(比如["email", "xxx", "password", "yyy"]),不是服务端需要的键值对象结构({"email":"xxx", "password":"yyy"})。
修正后的客户端JavaScript代码
'use strict' const form = document.getElementById('form'); const url = "http://localhost:8080/api/user/login"; form.addEventListener('submit', (e) => { e.preventDefault(); // 将FormData转换为标准键值对象 const formData = new FormData(form); const requestData = Object.fromEntries(formData); fetch(url, { method: "POST", // 传递正确的Content-Type头 headers: { "Content-Type": "application/json" }, // 发送JSON格式的请求体 body: JSON.stringify(requestData) }) .then(response => response.json()) .then(result => console.log(result)) .catch(error => console.log('error', error)); });
内容的提问来源于stack exchange,提问作者Victor Bej
相关产品推荐
相关产品推荐

