Golang中HTTP响应状态码200但返回空body的问题如何解决

Golang中HTTP响应状态码200但返回空body的问题如何解决 我正在尝试编写一个库来与 Jetbrains Space HTTP API 进行交互,但遇到了一些问题。当我向他们的 API 提交 HTTP 请求时,即使实际情况并非如此,我总是收到 200 OK 状态码。

以下是我发送给服务器的请求:

POST /api/http/projects HTTP/1.1
Host: dragonfly.jetbrains.space
User-Agent: Go-http-client/1.1
Content-Length: 78
Authorization: Bearer  <oauth2 access token>
Accept-Encoding: gzip
Accept: application/json

{"description":"","key":{"key":"ABC"},"name":"Test","private":true,"tags":[]}

使用的代码如下:

    buf := bytes.NewBuffer(nil)
	_ = json.NewEncoder(buf).Encode(map[string]interface{}{
		"key": map[string]interface{}{"key": "ABC"},
		"name": "Test",
		"private": true,
		"description": "",
		"tags": []string{},
	})

	req, err := http.NewRequest("POST", "https://dragonfly.jetbrains.space/api/http/projects", buf)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer <oauth2 access token>")
    req.Header.Set("Accept", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}

我期望看到的是 403 Forbidden 状态码,并附带以下错误信息:

{"error":"permission-denied","error_description":"Only users are allowed to perform this operation"}

但我最终得到的是:

HTTP/2.0 200 OK
Content-Length: 0
Date: Sat, 23 May 2020 10:13:21 GMT
Vary: Origin

对于这些错误,使用 Go HTTP 客户端时,我似乎总是收到 200 OK 状态码且没有响应体数据。我尝试用 JavaScript 发送相同的请求,结果似乎正常,这让我相信这是 Go HTTP 客户端的某个特殊问题。

同样的问题也出现在不同的端点上,但奇怪的是,如果对端点的调用成功,它却能正常工作。(即一个真正的 200 OK)

有人能给我一些指点吗?

感谢您提供的任何帮助。


更多关于Golang中HTTP响应状态码200但返回空body的问题如何解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

事实证明,缺少一个请求头导致端点返回了状态码为200 OK但无响应体的结果。显然,我之前使用的JavaScript库会自动包含这个请求头。

更多关于Golang中HTTP响应状态码200但返回空body的问题如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个典型的HTTP/2协议处理问题。Jetbrains Space API在某些错误情况下会发送HTTP/2的RST_STREAM帧,而Go的HTTP客户端在遇到这种情况时会返回200状态码和空响应体。

以下是解决方案:

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
)

func main() {
	buf := bytes.NewBuffer(nil)
	_ = json.NewEncoder(buf).Encode(map[string]interface{}{
		"key":         map[string]interface{}{"key": "ABC"},
		"name":        "Test",
		"private":     true,
		"description": "",
		"tags":        []string{},
	})

	req, err := http.NewRequest("POST", "https://dragonfly.jetbrains.space/api/http/projects", buf)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer <oauth2 access token>")
	req.Header.Set("Accept", "application/json")

	// 方案1:强制使用HTTP/1.1
	transport := &http.Transport{
		ForceAttemptHTTP2: false, // 禁用HTTP/2
	}
	client := &http.Client{
		Transport: transport,
	}

	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	fmt.Printf("Status: %d\n", resp.StatusCode)
	
	// 读取响应体
	var result map[string]interface{}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		fmt.Printf("Error reading response: %v\n", err)
	} else {
		fmt.Printf("Response: %v\n", result)
	}
}

或者使用更精细的HTTP/2配置:

// 方案2:配置HTTP/2的ReadIdleTimeout
transport := &http.Transport{
	ReadIdleTimeout: 30 * time.Second, // 防止HTTP/2连接过早关闭
}
client := &http.Client{
	Transport: transport,
	Timeout:   30 * time.Second,
}

resp, err := client.Do(req)

如果问题仍然存在,可以添加详细的错误处理来诊断:

resp, err := client.Do(req)
if err != nil {
    // 检查是否是HTTP/2 RST_STREAM错误
    if strings.Contains(err.Error(), "stream reset") || 
       strings.Contains(err.Error(), "RST_STREAM") {
        fmt.Println("HTTP/2 stream was reset by server")
    }
    panic(err)
}

// 检查响应体是否为空
body, err := io.ReadAll(resp.Body)
if err != nil {
    fmt.Printf("Error reading body: %v\n", err)
}
if len(body) == 0 && resp.StatusCode == 200 {
    fmt.Println("Received empty body with 200 status - likely HTTP/2 issue")
}

这个问题在Go 1.16及更高版本中更为常见,因为默认启用了HTTP/2。强制使用HTTP/1.1是最可靠的解决方案。

回到顶部