Golang中Http Post请求返回nil的解决方案

Golang中Http Post请求返回nil的解决方案 大家好。

我正在尝试通过一个 HTTP(使用 net/http 模块)的 POST 请求来获取 PayPal 的令牌。 示例链接:example 我尝试了解码和解组,以及在网上找到的各种方法。

respBody, err := ioutil.ReadAll(resp.Body)
json.Unmarshal([]byte(respBody), &info) // info == []
json.NewDecoder(resp.Body).Decode(&res) // res == nil

我可以看到字节形式的整数或转换后的字符串,但看不到 JSON 结构。 我尝试使用了所有这些:

var res interface{}
var res []interface{}
var res map[string]interface{}

我是 Go 语言的新手。


更多关于Golang中Http Post请求返回nil的解决方案的实战教程也可以访问 https://www.itying.com/category-94-b0.html

8 回复

Lejla94:

"grant_type=client_credentials"

不是有效的 JSON 语法

更多关于Golang中Http Post请求返回nil的解决方案的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我认为它内部没有引号来使其成为一个真正的JSON字符串,但由于他试图将其解析为映射,字符串很可能不是他所期望的。

为澄清说明:我正确地将

"grant_type=client_credentials"

传递给了请求,但没有尝试获取响应,所以我必须执行

res, _ := client.Do(req)

它本身是一个有效的JSON字符串值。

不过,从行内注释很难判断,string(respBody) 到底是JSON值 "foo=bar"(在Go中为 "\"foo=bar\"")还是Go值 "foo=bar"

感谢大家的帮助。 我重新审视了一下,发现我之前做错了。 我在GitHub上看到了一些示例,意识到我错误地使用了reqresp。 因此,我将这段代码:

req, err := http.NewRequest("POST", "https://api-m.sandbox.paypal.com/v1/oauth2/token", (strings.NewReader(data.Encode())))

修改为这样做:

client := &http.Client{}
res, _ := client.Do(req)

最后是:

json.NewDecoder(res.Body).Decode(&info)

你好

我认为你对JSON有些混淆。 我不太理解你的一些内容。 这里有一个有效的示例:如何在Golang中解析JSON? - GeeksforGeeks

无论如何,字节应该使用 string(var) 转换为字符串。

// 示例代码:将字节数组转换为字符串
package main

import (
    "fmt"
)

func main() {
    byteArray := []byte{72, 101, 108, 108, 111} // "Hello" 的ASCII码
    str := string(byteArray)
    fmt.Println(str) // 输出: Hello
}

如何在Go中将字节数组转换为字符串

我想获取POST请求的响应。 但结果总是空的,即 == []== nil。 例如:

resp, err := http.NewRequest("POST", "https://api-m.sandbox.paypal.com/v1/oauth2/token", (strings.NewReader(data.Encode())))
respBody, err := io.ReadAll(resp.Body) // string(respBody) 是 "grant_type=client_credentials"

var info []interface{}
json.Unmarshal([]byte(string(respBody)), &info) // info 是 []

var res interface{}
var someErr = json.NewDecoder(resp.Body).Decode(&res) // res 和 someErr 都是 <nil>

如果我使用 map[string]interface{},结果是 map[]。 所以我猜测响应返回的是该类型的默认值。 期望的结果应该是一个包含访问令牌和其他字段的对象(结构体)。 我已经看过如何反序列化JSON等示例。 我到底遗漏了什么。

在Golang中处理HTTP POST请求返回nil的问题,通常是由于响应体读取或JSON解码的问题。根据你的代码,这里有几个关键点需要注意:

  1. 响应体只能读取一次resp.Body是一个io.ReadCloser,读取后会被消耗。如果你多次读取,第二次会得到空数据。
  2. 检查HTTP状态码:确保请求成功(状态码200)。
  3. 关闭响应体:使用defer确保响应体被关闭。

以下是修复后的示例代码:

package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "strings"
)

func main() {
    url := "https://api.sandbox.paypal.com/v1/oauth2/token"
    payload := strings.NewReader("grant_type=client_credentials")
    
    req, err := http.NewRequest("POST", url, payload)
    if err != nil {
        fmt.Printf("创建请求失败: %v\n", err)
        return
    }
    
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
    req.SetBasicAuth("CLIENT_ID", "SECRET")
    
    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        fmt.Printf("请求失败: %v\n", err)
        return
    }
    defer resp.Body.Close()
    
    // 检查HTTP状态码
    if resp.StatusCode != http.StatusOK {
        bodyBytes, _ := io.ReadAll(resp.Body)
        fmt.Printf("请求失败,状态码: %d, 响应: %s\n", resp.StatusCode, string(bodyBytes))
        return
    }
    
    // 方法1: 使用io.ReadAll和json.Unmarshal
    bodyBytes, err := io.ReadAll(resp.Body)
    if err != nil {
        fmt.Printf("读取响应体失败: %v\n", err)
        return
    }
    
    var result map[string]interface{}
    if err := json.Unmarshal(bodyBytes, &result); err != nil {
        fmt.Printf("JSON解码失败: %v\n", err)
        return
    }
    
    fmt.Printf("响应数据: %v\n", result)
    
    // 或者方法2: 使用json.NewDecoder
    // 注意:resp.Body已经被读取,这里需要重新创建请求或使用保存的bodyBytes
    // var result2 map[string]interface{}
    // if err := json.NewDecoder(strings.NewReader(string(bodyBytes))).Decode(&result2); err != nil {
    //     fmt.Printf("JSON解码失败: %v\n", err)
    //     return
    // }
}

关键修改:

  1. 添加了HTTP状态码检查,PayPal API通常会在错误时返回非200状态码。
  2. 使用defer resp.Body.Close()确保资源释放。
  3. 使用map[string]interface{}来接收JSON对象。
  4. 如果响应是数组,使用[]interface{}

如果PayPal返回的是数组格式,修改解码部分:

var result []interface{}
if err := json.Unmarshal(bodyBytes, &result); err != nil {
    fmt.Printf("JSON解码失败: %v\n", err)
    return
}

调试建议:先打印原始响应字符串查看实际返回的数据格式:

bodyBytes, _ := io.ReadAll(resp.Body)
fmt.Printf("原始响应: %s\n", string(bodyBytes))

这样可以帮助你确定PayPal API实际返回的数据结构。

回到顶部