Golang处理畸形HTTP版本字符串问题:来自svc_a的POST请求示例"POST /proxy HTTP/1.1"

Golang处理畸形HTTP版本字符串问题:来自svc_a的POST请求示例"POST /proxy HTTP/1.1" (1) 我有一个HTTP客户端,它向HTTP服务器发送以下请求: http.NewRequest(“POST”, “http://localhost:9090/proxy”, strings.NewReader(“This is a POST request from svc_a”))

(2) HTTP服务器通过Go通道将请求对象发送给一个函数(TCP客户端),TCP客户端将HTTP请求作为其有效载荷发送给TCP服务器。

(3) TCP服务器读取TCP有效载荷,并使用http.ReadRequest(x *bufio.Reader)从中创建HTTP请求。 (4) 将响应发送给TCP客户端。

(5) 当我通过同一个套接字连接从TCP客户端向TCP服务器发送两个请求时,有时TCP客户端能成功收到响应,但有时TCP服务器会抛出错误,例如格式错误的HTTP版本“{原始HTTP请求的某部分}”或格式错误的HTTP请求“{” 在http.ReadRequest()这一行。

这里可能是什么原因?是否是由TCP分段引起的?


更多关于Golang处理畸形HTTP版本字符串问题:来自svc_a的POST请求示例"POST /proxy HTTP/1.1"的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

看起来HTTP服务器误解了两个连续HTTP请求的边界。你介意捕获并发布pcap文件吗?有几个在线工具可以共享和查看pcap文件(例如cloudshark.org上的CS Enterprise,WireShark的在线版本

更多关于Golang处理畸形HTTP版本字符串问题:来自svc_a的POST请求示例"POST /proxy HTTP/1.1"的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中处理HTTP请求时,如果遇到畸形HTTP版本字符串错误,通常是由于TCP流中的数据边界问题导致的。当通过同一个TCP连接发送多个请求时,如果读取缓冲区的数据没有正确分割,http.ReadRequest可能会读取到不完整的请求数据或跨请求的数据,从而解析失败。

以下是一个示例,展示如何通过正确管理TCP连接中的数据读取来避免这个问题:

package main

import (
    "bufio"
    "bytes"
    "fmt"
    "io"
    "net/http"
    "strings"
)

// 模拟TCP服务器读取HTTP请求
func readHTTPRequestsFromTCP(conn io.Reader) {
    reader := bufio.NewReader(conn)
    for {
        // 使用http.ReadRequest读取请求
        req, err := http.ReadRequest(reader)
        if err != nil {
            if err == io.EOF {
                break
            }
            fmt.Printf("读取请求失败: %v\n", err)
            break
        }
        defer req.Body.Close()

        // 处理请求
        body, _ := io.ReadAll(req.Body)
        fmt.Printf("收到请求: %s %s 版本: %s 主体: %s\n", req.Method, req.URL.Path, req.Proto, string(body))
    }
}

// 模拟TCP客户端发送HTTP请求
func sendHTTPRequestOverTCP(writer io.Writer, req *http.Request) error {
    // 将HTTP请求写入缓冲区
    var buf bytes.Buffer
    if err := req.Write(&buf); err != nil {
        return err
    }
    // 通过TCP连接发送
    _, err := writer.Write(buf.Bytes())
    return err
}

func main() {
    // 创建内存中的管道模拟TCP连接
    serverConn, clientConn := io.Pipe()

    // 启动模拟TCP服务器
    go func() {
        readHTTPRequestsFromTCP(serverConn)
        serverConn.Close()
    }()

    // 模拟第一个请求
    req1, _ := http.NewRequest("POST", "http://localhost:9090/proxy", strings.NewReader("第一个请求"))
    if err := sendHTTPRequestOverTCP(clientConn, req1); err != nil {
        fmt.Printf("发送请求1失败: %v\n", err)
    }

    // 模拟第二个请求
    req2, _ := http.NewRequest("POST", "http://localhost:9090/proxy", strings.NewReader("第二个请求"))
    if err := sendHTTPRequestOverTCP(clientConn, req2); err != nil {
        fmt.Printf("发送请求2失败: %v\n", err)
    }

    clientConn.Close()
}

在这个示例中,每个HTTP请求通过req.Write完整地序列化后写入TCP连接,确保请求之间没有数据粘连。在TCP服务器端,bufio.Reader会按需读取数据,直到http.ReadRequest解析出一个完整的HTTP请求。

如果问题仍然出现,检查TCP客户端是否在发送请求后正确刷新了数据,以及TCP服务器是否在读取请求时正确处理了数据边界。使用bufio.Reader并确保每个请求完整发送可以避免因TCP分段导致的解析错误。

回到顶部