golang - tcpclient 当我发送 http 请求时,它总是 return(错误请求 400)
golang - tcpclient when I send http request, it always return (bad request 400)
我试图通过 GOLang 中的 TCP/TLS 套接字发送 HTTP 请求,但是当我尝试发送它时,无论主机是什么,它总是 returns(错误请求 400 ), 所以我想一定是我用TCP/TLS发送请求的方式有问题,搜索了一下,找了一种方法去做我想做的事情,但是没有结果:
package main
import (
"crypto/rand"
"crypto/tls"
"fmt"
"net"
"strings"
)
func main() {
headers := make(map[string]string)
headers["Accept"] = "application/json"
request := parseRequest("httpbin.org", "/get", "get", headers, nil, "")
println(request)
tcpConn, err := net.Dial("tcp", "httpbin.org:443")
if err != nil {
panic(err)
}
cf := &tls.Config{Rand: rand.Reader, InsecureSkipVerify: true}
ssl := tls.Client(tcpConn, cf)
if err != nil {
panic(err)
}
defer ssl.Close()
n, err := ssl.Write([]byte(request))
if err != nil {
fmt.Println(n, err)
return
}
buf := make([]byte, 1024)
n, err = ssl.Read(buf)
if err != nil {
fmt.Println(n, err)
return
}
println(string(buf[:n]))
}
func parseRequest(host string, path string, method string, headers map[string]string, data map[string]string, rawData string) string {
method = strings.ToUpper(method)
rawRequest := fmt.Sprintf(`%s %s HTTP/1.1\r\n`, strings.ToUpper(method), path)
if method == `GET` && (data != nil || rawData != ``) {
var rawQuery string
if rawData != `` {
rawQuery = rawData
} else {
i := 0
for key, value := range data {
if i == len(data)-1 {
rawQuery += fmt.Sprintf(`%s=%s`, key, value)
} else {
rawQuery += fmt.Sprintf(`%s=%s&`, key, value)
}
i++
}
}
query := fmt.Sprintf(`%s?%s`, path, rawQuery)
rawRequest = fmt.Sprintf(`%s %s HTTP/1.1\r\n`, strings.ToUpper(method), query)
}
var rawHeaders string
for key, value := range headers {
rawHeaders += fmt.Sprintf(`%s: %s\r\n`, key, value)
}
if !strings.Contains(strings.ToLower(rawHeaders), `host`) {
rawRequest += fmt.Sprintf(`Host: %s\r\n`, host)
}
rawRequest += fmt.Sprintf(`%s\r\n`, rawHeaders)
if method == `POST` && (data != nil || rawData != ``) {
if rawData != `` {
rawRequest += rawData
} else {
i := 0
for key, value := range data {
if i == len(data)-1 {
rawRequest += fmt.Sprintf(`%s=%s`, key, value)
} else {
rawRequest += fmt.Sprintf(`%s=%s&`, key, value)
}
i++
}
}
}
return rawRequest
}
在 Go 中,反引号 `
用于表示原始字符串,根据 spec:
Raw string literals are character sequences between back quotes, as in
`foo`. Within the quotes, any character may appear except back quote.
The value of a raw string literal is the string composed of the
uninterpreted (implicitly UTF-8-encoded) characters between the
quotes; in particular, backslashes have no special meaning and the
string may contain newlines. Carriage return characters ('\r') inside
raw string literals are discarded from the raw string value.
这意味着,您代码中的所有 \r\n
都不会被解释为回车符 returns 或换行符。您应该改为使用双引号 "
.
作为一般风格指南,除非需要大量转义,否则应该使用双引号。
我试图通过 GOLang 中的 TCP/TLS 套接字发送 HTTP 请求,但是当我尝试发送它时,无论主机是什么,它总是 returns(错误请求 400 ), 所以我想一定是我用TCP/TLS发送请求的方式有问题,搜索了一下,找了一种方法去做我想做的事情,但是没有结果:
package main
import (
"crypto/rand"
"crypto/tls"
"fmt"
"net"
"strings"
)
func main() {
headers := make(map[string]string)
headers["Accept"] = "application/json"
request := parseRequest("httpbin.org", "/get", "get", headers, nil, "")
println(request)
tcpConn, err := net.Dial("tcp", "httpbin.org:443")
if err != nil {
panic(err)
}
cf := &tls.Config{Rand: rand.Reader, InsecureSkipVerify: true}
ssl := tls.Client(tcpConn, cf)
if err != nil {
panic(err)
}
defer ssl.Close()
n, err := ssl.Write([]byte(request))
if err != nil {
fmt.Println(n, err)
return
}
buf := make([]byte, 1024)
n, err = ssl.Read(buf)
if err != nil {
fmt.Println(n, err)
return
}
println(string(buf[:n]))
}
func parseRequest(host string, path string, method string, headers map[string]string, data map[string]string, rawData string) string {
method = strings.ToUpper(method)
rawRequest := fmt.Sprintf(`%s %s HTTP/1.1\r\n`, strings.ToUpper(method), path)
if method == `GET` && (data != nil || rawData != ``) {
var rawQuery string
if rawData != `` {
rawQuery = rawData
} else {
i := 0
for key, value := range data {
if i == len(data)-1 {
rawQuery += fmt.Sprintf(`%s=%s`, key, value)
} else {
rawQuery += fmt.Sprintf(`%s=%s&`, key, value)
}
i++
}
}
query := fmt.Sprintf(`%s?%s`, path, rawQuery)
rawRequest = fmt.Sprintf(`%s %s HTTP/1.1\r\n`, strings.ToUpper(method), query)
}
var rawHeaders string
for key, value := range headers {
rawHeaders += fmt.Sprintf(`%s: %s\r\n`, key, value)
}
if !strings.Contains(strings.ToLower(rawHeaders), `host`) {
rawRequest += fmt.Sprintf(`Host: %s\r\n`, host)
}
rawRequest += fmt.Sprintf(`%s\r\n`, rawHeaders)
if method == `POST` && (data != nil || rawData != ``) {
if rawData != `` {
rawRequest += rawData
} else {
i := 0
for key, value := range data {
if i == len(data)-1 {
rawRequest += fmt.Sprintf(`%s=%s`, key, value)
} else {
rawRequest += fmt.Sprintf(`%s=%s&`, key, value)
}
i++
}
}
}
return rawRequest
}
在 Go 中,反引号 `
用于表示原始字符串,根据 spec:
Raw string literals are character sequences between back quotes, as in `foo`. Within the quotes, any character may appear except back quote. The value of a raw string literal is the string composed of the uninterpreted (implicitly UTF-8-encoded) characters between the quotes; in particular, backslashes have no special meaning and the string may contain newlines. Carriage return characters ('\r') inside raw string literals are discarded from the raw string value.
这意味着,您代码中的所有 \r\n
都不会被解释为回车符 returns 或换行符。您应该改为使用双引号 "
.
作为一般风格指南,除非需要大量转义,否则应该使用双引号。