Golang中如何让http.Server处理来自连接的请求
Golang中如何让http.Server处理来自连接的请求 我当前的目标:编写一个能够解密HTTPS连接的代理服务器。
问题如下:在http.Handler中劫持连接并完成TLS握手后,我获得了一个包含HTTP流量的解密连接,我希望使用http.Server来处理这些流量,这样我就不需要自己编写HTTP请求处理循环。
如何以最正确且无需额外内存分配的方式实现这一点?
在fasthttp库中,有一个很好的fasthttp.ServeConn方法,我能在net.http中实现类似的功能吗?
我也不理解在你的示例中发生了什么,所以我们两个都有同样的困惑。当你处于处理函数中时,TLS握手和HTTP请求已经完成,你看到的请求是明文的。此时通过劫持来启动另一个握手对我来说没有意义。这不是代理服务器的做法。
// 代码示例保留原样
func main() {
fmt.Println("hello world")
}
更多关于Golang中如何让http.Server处理来自连接的请求的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
听起来你正在构建一个HTTPS代理。net/http/httputil.ReverseProxy类型很适合这个场景,它允许你在传输过程中检查和修改请求和响应。相比于使用劫持等技术,这个方案是否更适合你的需求?
另外,如果你想通过常规的http.Handler来处理传入请求,为什么不直接使用标准的监听http.Server呢?
func main() {
fmt.Println("hello world")
}
我不太理解在中间人攻击的情况下,httputil.ReverseProxy 如何帮助我。
通过一个示例来说明(代码注释中的问题):
http.HandleFunc("/hijack", func(w http.ResponseWriter, r *http.Request) {
hj, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError)
return
}
conn, bufrw, err := hj.Hijack()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 不要忘记关闭连接:
defer conn.Close()
tls_conn := tls.Server(conn, tlsConfig)
if err := tls_conn.Handshake(); err != nil {
return nil, fmt.Errorf("Handshake error: %s", err)
}
// 待办:如何使用 http.Server 处理来自 tls_conn 的 http 流?
})
在Go标准库的net/http包中,虽然没有像fasthttp那样直接的ServeConn方法,但你可以通过劫持连接并使用http.Server的底层处理机制来实现类似功能。以下是实现方案:
核心解决方案
package main
import (
"bufio"
"context"
"crypto/tls"
"fmt"
"net"
"net/http"
"time"
)
type connWrapper struct {
net.Conn
}
func (cw *connWrapper) Close() error {
return cw.Conn.Close()
}
// 处理解密后的TLS连接
func handleDecryptedConnection(conn net.Conn, server *http.Server) error {
// 创建连接包装器
wrappedConn := &connWrapper{Conn: conn}
// 使用Server的底层连接处理机制
return server.Serve(net.Listener(&singleConnListener{conn: wrappedConn}))
}
// 单连接监听器实现
type singleConnListener struct {
conn net.Conn
done bool
}
func (l *singleConnListener) Accept() (net.Conn, error) {
if l.done {
return nil, fmt.Errorf("listener closed")
}
l.done = true
return l.conn, nil
}
func (l *singleConnListener) Close() error {
return l.conn.Close()
}
func (l *singleConnListener) Addr() net.Addr {
return l.conn.LocalAddr()
}
// 代理服务器处理函数
func proxyHandler(server *http.Server) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// 劫持连接
hijacker, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "Hijacking not supported", http.StatusInternalServerError)
return
}
clientConn, _, err := hijacker.Hijack()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 发送连接建立响应
fmt.Fprintf(clientConn, "HTTP/1.1 200 Connection established\r\n\r\n")
// 执行TLS握手(这里需要你实际的TLS配置)
tlsConfig := &tls.Config{
// 你的TLS配置
}
tlsConn := tls.Server(clientConn, tlsConfig)
if err := tlsConn.Handshake(); err != nil {
tlsConn.Close()
return
}
// 处理解密后的连接
go handleDecryptedConnection(tlsConn, server)
}
}
完整示例
func main() {
// 创建HTTP服务器
server := &http.Server{
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "处理请求: %s %s\n", r.Method, r.URL.Path)
}),
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
}
// 代理服务器
proxyServer := &http.Server{
Addr: ":8080",
Handler: proxyHandler(server),
}
fmt.Println("代理服务器运行在 :8080")
if err := proxyServer.ListenAndServe(); err != nil {
fmt.Printf("服务器错误: %v\n", err)
}
}
更高效的实现方式
如果你需要更低的延迟和内存分配,可以直接使用bufio.Reader和HTTP请求解析:
func handleHTTPConnection(conn net.Conn, handler http.Handler) {
defer conn.Close()
reader := bufio.NewReader(conn)
writer := bufio.NewWriter(conn)
for {
// 读取HTTP请求
req, err := http.ReadRequest(reader)
if err != nil {
break
}
// 创建响应写入器
rw := &responseWriter{
conn: conn,
writer: writer,
header: make(http.Header),
}
// 处理请求
handler.ServeHTTP(rw, req)
// 刷新缓冲区
if err := writer.Flush(); err != nil {
break
}
// 如果不是keep-alive,则退出循环
if !isKeepAlive(req) {
break
}
}
}
// 自定义响应写入器
type responseWriter struct {
conn net.Conn
writer *bufio.Writer
header http.Header
status int
}
func (rw *responseWriter) Header() http.Header {
return rw.header
}
func (rw *responseWriter) Write(data []byte) (int, error) {
return rw.writer.Write(data)
}
func (rw *responseWriter) WriteHeader(statusCode int) {
rw.status = statusCode
}
func isKeepAlive(req *http.Request) bool {
return req.Close == false
}
关键要点
-
使用
singleConnListener:通过实现net.Listener接口来包装单个连接,让http.Server能够处理该连接。 -
避免额外内存分配:重用连接和缓冲区,减少GC压力。
-
正确处理连接生命周期:确保连接在适当的时候关闭,避免资源泄漏。
-
性能优化:对于高并发场景,可以考虑使用连接池和对象重用模式。
这种方法让你能够利用标准库的HTTP处理能力,同时保持对底层连接的控制,实现高效的代理服务器功能。

