Golang API请求中空键值未被发送的问题解析

Golang API请求中空键值未被发送的问题解析 我在使用Go代码时遇到了一个问题。我正在调用一个API,请求体有时只包含键而没有值,内容类型是application/x-www-form-urlencoded。Go似乎没有发送空的键,导致API调用失败。

req, _ := http.NewRequest("POST", jmb_gid_url,strings.NewReader(r.Form.Encode()))
req.Header.Add("Authorization", r.Header.Get("Authorization"))
req.Header.Add("Content-Type", r.Header.Get("Content-Type"))

更多关于Golang API请求中空键值未被发送的问题解析的实战教程也可以访问 https://www.itying.com/category-94-b0.html

5 回复

如何设置 r.Form?

更多关于Golang API请求中空键值未被发送的问题解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


if err := r.ParseForm(); err != nil {
// 处理错误
}

问题已解决,原来是API对某些键有特定值要求,比如国家字段必须使用"US",当我尝试用"FR"调用时就失败了。
感谢 🙂

那么你接收一个 application/x-www-form-urlencoded 请求并转发它吗?你需要处理这种内容类型吗?不能采用 REST 方式吗?这样能对事务有更多控制权?

我简要查看了这些方法的源代码,认为它们不会丢弃零值。你记录了 ParseForm 和 Encode 的两个值吗?

在Go语言的net/url包中,Values.Encode()方法会过滤掉值为空的键值对,这是导致空键未被发送的根本原因。当使用r.Form.Encode()时,任何值为空的表单字段都会被自动忽略。

以下是问题重现和解决方案:

问题重现示例:

package main

import (
    "fmt"
    "net/url"
)

func main() {
    form := url.Values{}
    form.Add("key1", "value1")
    form.Add("emptyKey", "")  // 空值键
    form.Add("key2", "value2")
    
    encoded := form.Encode()
    fmt.Printf("编码结果: %s\n", encoded)
    // 输出: key1=value1&key2=value2
    // emptyKey 被过滤掉了
}

解决方案:手动构建请求体

使用url.ValuesEncode()方法无法保留空值键,需要手动构建URL编码的字符串:

package main

import (
    "net/http"
    "net/url"
    "sort"
    "strings"
)

// 自定义编码函数,保留空值键
func encodeWithEmptyKeys(values url.Values) string {
    if values == nil {
        return ""
    }
    
    var buf strings.Builder
    keys := make([]string, 0, len(values))
    for k := range values {
        keys = append(keys, k)
    }
    sort.Strings(keys)
    
    for i, k := range keys {
        if i > 0 {
            buf.WriteByte('&')
        }
        buf.WriteString(url.QueryEscape(k))
        buf.WriteByte('=')
        // 即使值为空也保留键
        if len(values[k]) > 0 {
            buf.WriteString(url.QueryEscape(values[k][0]))
        }
        // 对于空值,只写键和等号,不写值
    }
    return buf.String()
}

// 修改后的API请求代码
func makeAPIRequest(jmb_gid_url string, r *http.Request) (*http.Request, error) {
    // 解析表单
    if err := r.ParseForm(); err != nil {
        return nil, err
    }
    
    // 使用自定义编码保留空键
    body := encodeWithEmptyKeys(r.Form)
    
    req, err := http.NewRequest("POST", jmb_gid_url, strings.NewReader(body))
    if err != nil {
        return nil, err
    }
    
    req.Header.Add("Authorization", r.Header.Get("Authorization"))
    req.Header.Add("Content-Type", r.Header.Get("Content-Type"))
    
    return req, nil
}

验证示例:

func main() {
    form := url.Values{}
    form.Add("key1", "value1")
    form.Add("emptyKey", "")  // 空值键
    form.Add("key2", "value2")
    
    // 标准编码(会过滤空键)
    standard := form.Encode()
    fmt.Printf("标准编码: %s\n", standard)
    
    // 自定义编码(保留空键)
    custom := encodeWithEmptyKeys(form)
    fmt.Printf("自定义编码: %s\n", custom)
    // 输出: emptyKey=&key1=value1&key2=value2
}

这个解决方案通过手动构建URL编码字符串,确保了即使值为空的键也会被包含在请求体中,格式为emptyKey=,符合application/x-www-form-urlencoded的标准格式。

回到顶部