go语言解析HTTP包生成代码发送HTTP数据包
输入是从fiddler捕获的HTTP数据包
GET https://bbs.kanxue.com/ HTTP/1.1
Host: bbs.kanxue.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
sec-ch-ua: "Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
运行程序以后,粘贴上面的内容,然后回车即可。
需要注意的是,有的请求没有body部分,所以需要多一个回车。
package main
import (
"bufio"
"bytes"
"fmt"
"log"
"net/url"
"os"
"strings"
"text/template"
)
type Request struct {
Method string
URL string
//Headers []struct {
// Key string
// Value string
//}
Headers map[string]string
Body string
Proxy string
}
func main() {
reader := bufio.NewReader(os.Stdin)
// 读取并解析起始行
startLine, _ := reader.ReadString('\n')
method, reqURL, _ := parseStartLine(startLine)
// 读取并解析Header部分
headers := make(map[string]string)
for {
line, _ := reader.ReadString('\n')
if line == "\r\n" {
break
}
key, value := parseHeader(line)
headers[key] = value
}
delete(headers, "Content-Length")
// 读取Body部分
body, _ := reader.ReadString('\n')
//fmt.Println("Body: ", body)
// 输出解析结果
//fmt.Println("RequestMethod: ", method)
//fmt.Println("RequestURL: ", reqURL)
//fmt.Println("Headers: ", headers)
//fmt.Println("Body: ", body)
data := &Request{
Method: method,
URL: reqURL,
Headers: headers,
Body: body,
Proxy: "http://127.0.0.1:7788",
}
generate(data)
}
func replace(input, from, to string) string {
return strings.Replace(input, from, to, -1)
}
func generate(data *Request) {
// 从内存中获取数据,构造结构体
funcMap := template.FuncMap{"replace": replace}
// 定义模板
t := template.Must(template.New("codeTemplate").Funcs(funcMap).Parse(`
package main
import (
"bytes"
"fmt"
"io/ioutil"
"net/http"
"net/url"
)
func main() {
// 请求方法
method := "{{.Method}}"
urls := "{{.URL}}"
// 请求头
headers := map[string]string{
{{range $key, $value :=.Headers}}"{{$key}}": "{{replace $value "\"" "\\\""}}",
{{end}}
}
// 请求 body
body := ` + "`{{.Body}}`" + `
// 创建 HTTP 客户端
client := &http.Client{}
proxyStr := "{{.Proxy}}"
_, err := url.Parse(proxyStr)
{{if .Proxy}}
// 设置代理
proxyURL, err := url.Parse(proxyStr)
if err != nil {
fmt.Println("Error parsing proxy URL:", err)
return
}
// 设置 HTTP 客户端的代理
client.Transport = &http.Transport{Proxy: http.ProxyURL(proxyURL)}
{{end}}
// 创建 HTTP 请求
req, err := http.NewRequest(method, urls, bytes.NewBuffer([]byte(body)))
if err != nil {
fmt.Println("Error creating HTTP request:", err)
return
}
// 添加 HTTP 请求头
for key, value := range headers {
req.Header.Set(key, value)
}
// 发送 HTTP 请求
resp, err := client.Do(req)
if err != nil {
fmt.Println("Error sending HTTP request:", err)
return
}
defer resp.Body.Close()
// 读取 HTTP 响应体
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("Error reading HTTP response body:", err)
return
}
// 输出 HTTP 响应体
fmt.Println(string(respBody))
}
`))
// 渲染模板
var buf bytes.Buffer
if err := t.Execute(&buf, data); err != nil {
log.Fatalf("Failed to render template: %v", err)
}
// 将 Go 语言代码写入文件
file, err := os.Create("http_request.go")
if err != nil {
log.Fatalf("Failed to create file: %v", err)
}
defer file.Close()
if _, err := file.Write(buf.Bytes()); err != nil {
log.Fatalf("Failed to write file: %v", err)
}
fmt.Println("Go 语言程序生成成功,请通过 go run 命令运行 http_request.go 程序。")
}
// 解析HTTP请求起始行
func parseStartLine(startLine string) (string, string, error) {
// 移除行尾的回车换行符
startLine = strings.TrimSpace(startLine)
parts := strings.Split(startLine, " ")
if len(parts) != 3 {
return "", "", fmt.Errorf("Invalid Start Line: %s", startLine)
}
reqURL, err := url.Parse(parts[1])
if err != nil {
return "", "", err
}
return parts[0], reqURL.String(), nil
}
// 解析HTTP请求Header部分
func parseHeader(line string) (string, string) {
parts := strings.SplitN(line, ":", 2)
if len(parts) != 2 {
return "", ""
}
key := strings.TrimSpace(parts[0])
value := strings.TrimSpace(parts[1])
return key, value
}