Go向Rails API发送HTTP POST请求传参格式异常问题排查
问题根源
两次报错本质都是请求体JSON结构不符合Rails的参数解析规则:
- 第一版代码既没设置
Content-Type: application/json请求头,请求体还是手写的非标准JSON格式,Rails根本解析不到bar参数,直接抛出ParameterMissing错误 - 第二版代码虽然补对了请求头,但你把
bar字段对应的值提前转成了字符串,不是嵌套的JSON对象,Rails解析完拿到的params[:bar]是字符串类型,传给Bar.new初始化模型时自然触发类型错误
Rails对这类嵌套参数的解析要求很明确:提交对象类型的参数时,JSON结构必须是对象嵌套对象的格式,对应你的业务场景,合法的请求体长这样:
{ "bar": { "test": "对应字符串内容" } }
正确的Go客户端写法
不要手动拼接JSON字符串,直接构造嵌套的map或结构体交给json.Marshal序列化即可,参考实现:
for _, data := range attributes { // 提示:http.Client是协程安全的,不需要每次循环新建,全局初始化一次复用性能更好 client := &http.Client{} // 构造嵌套结构:bar字段对应的值是包含test属性的对象,不是字符串 requestBody := map[string]interface{}{ "bar": map[string]string{ "test": data, }, } // 直接序列化整个嵌套结构,不要提前把内部对象转成字符串 bodyBytes, err := json.Marshal(requestBody) if err != nil { log.Fatalf("JSON序列化失败: %v", err) } req, err := http.NewRequest( "POST", "http://localhost:3000/bars.json", bytes.NewReader(bodyBytes), ) if err != nil { log.Fatalf("构造请求失败: %v", err) } // 配置JSON请求头 req.Header.Set("Content-Type", "application/json; charset=UTF-8") resp, err := client.Do(req) if err != nil { log.Fatalf("发送请求失败: %v", err) } // 释放响应体资源 defer resp.Body.Close() // 此处补充自己的响应处理逻辑 }
额外优化建议
http.Client是协程安全的,不需要在每次循环中新建实例,全局初始化一次复用即可,能减少不必要的资源开销- 不要用
fmt.Sprintf手动拼接JSON字符串,遇到特殊字符、引号时很容易出现格式错误,所有JSON序列化逻辑交给标准库encoding/json处理即可,它会自动完成转义 - 请求发送完成后记得调用
resp.Body.Close()释放TCP连接,否则会造成连接泄漏
内容的提问来源于stack exchange,提问作者CJG
相关产品推荐
相关产品推荐

