Golang中TLS与Chrome持久性的问题排查

Golang中TLS与Chrome持久性的问题排查 我正在使用 crypto/tls 和 Go 1.12.1 编写一个 SAAS 服务器。我使用 net 包,因此在 TCP 层面进行通信,而不是 net/http。

当我使用 Firefox、Edge 以及令人惊讶的 IE rv 11 显示登录界面时,TCP 连接保持打开状态超过一分钟;而 Chrome 在接收到登录界面后立即关闭连接。

Chrome 显示我的 HTTP 头部的截图: chrome3

显示 Firefox、Edge 和 Chrome 的截图: chrome2

任何想法都将不胜感激。如果我能找到一个有用的 Chrome 问题论坛,我会在那里发布这个问题。

展示问题的链接是 http://baffleplates.com:3081,这是我当前的开发服务器。Go 1.11.8 也存在同样的问题。


更多关于Golang中TLS与Chrome持久性的问题排查的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复

我的解决方案是使用WebSocket,它在浏览器支持方面更加一致。

希望这能为其他人节省一些时间。

更多关于Golang中TLS与Chrome持久性的问题排查的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


从你提供的信息来看,问题很可能与 TLS 配置或 HTTP 响应头中的某些字段有关,这些字段在 Chrome 中触发了不同的连接管理行为。以下是一些可能的原因和解决方案:

可能的原因分析

  1. TLS 配置差异:Chrome 可能对 TLS 版本、密码套件或证书有更严格的要求
  2. HTTP 头问题:缺少必要的头字段或值不符合 Chrome 的预期
  3. 连接保持机制:Chrome 可能对 ConnectionKeep-Alive 头的处理与其他浏览器不同

解决方案示例代码

以下是改进的 Go TLS 服务器实现,包含更完整的 HTTP 响应头:

package main

import (
    "crypto/tls"
    "fmt"
    "net"
    "time"
)

func main() {
    // 加载证书和密钥
    cert, err := tls.LoadX509KeyPair("server.crt", "server.key")
    if err != nil {
        panic(err)
    }

    // 配置 TLS
    tlsConfig := &tls.Config{
        Certificates: []tls.Certificate{cert},
        MinVersion:   tls.VersionTLS12, // 明确指定 TLS 1.2
        CipherSuites: []uint16{
            tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
            tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
        },
    }

    // 监听 TCP 连接
    listener, err := tls.Listen("tcp", ":3081", tlsConfig)
    if err != nil {
        panic(err)
    }
    defer listener.Close()

    fmt.Println("Server listening on :3081")

    for {
        conn, err := listener.Accept()
        if err != nil {
            fmt.Println("Accept error:", err)
            continue
        }
        go handleConnection(conn)
    }
}

func handleConnection(conn net.Conn) {
    defer conn.Close()

    // 设置读取超时
    conn.SetReadDeadline(time.Now().Add(30 * time.Second))

    // 读取客户端请求
    buffer := make([]byte, 1024)
    n, err := conn.Read(buffer)
    if err != nil {
        return
    }

    // 检查是否为 HTTP 请求
    if n > 0 {
        // 构建完整的 HTTP 响应头
        response := "HTTP/1.1 200 OK\r\n" +
            "Content-Type: text/html; charset=utf-8\r\n" +
            "Connection: keep-alive\r\n" +
            "Keep-Alive: timeout=60\r\n" +
            "Content-Length: 1024\r\n" +
            "\r\n" +
            "<!DOCTYPE html><html><head><title>Login</title></head>" +
            "<body><h1>Login Page</h1></body></html>"

        // 发送响应
        _, err = conn.Write([]byte(response))
        if err != nil {
            return
        }

        // 保持连接打开一段时间
        time.Sleep(60 * time.Second)
    }
}

关键改进点

  1. 明确的 TLS 配置

    • 指定 TLS 1.2 作为最低版本
    • 使用现代密码套件
  2. 完整的 HTTP 响应头

    • 包含 Connection: keep-alive
    • 包含 Keep-Alive: timeout=60
    • 正确的 Content-Length
  3. 连接管理

    • 设置读取超时
    • 明确保持连接

调试建议

在服务器端添加日志来监控连接状态:

func handleConnection(conn net.Conn) {
    remoteAddr := conn.RemoteAddr().String()
    fmt.Printf("New connection from: %s\n", remoteAddr)
    defer func() {
        fmt.Printf("Connection closed: %s\n", remoteAddr)
    }()
    
    // ... 原有的处理逻辑
}

这个实现应该能解决 Chrome 过早关闭连接的问题。如果问题仍然存在,建议检查 Chrome 开发者工具中的网络标签,查看具体的 TLS 握手细节和 HTTP 头信息。

回到顶部