go - Http Over TLS Golang 未接收 header

标签 go ssl https request-headers tls1.3

我从客户端发送“用户代理 header ”,但没有在服务器端接收,但当我使用浏览器时它可以工作。

服务器代码:

package main

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

const (
  defaultServerDomain = "localhost:443"
  certPemPath = "./selfsigned.crt"
  privKeyPath = "./selfsigned.key"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/demo/echo", func(w http.ResponseWriter, req *http.Request) {
    w.Header().Add("Strict-Transport-Security", "max-age=63072000; includeSubDomains")
    w.Write([]byte("This is an example server.\n"))
    fmt.Printf("\n\nUserAgent : %s", req.UserAgent())

  })
  cfg := &tls.Config{
    MinVersion:               tls.VersionTLS12,
    CurvePreferences:         []tls.CurveID{tls.CurveP521, tls.CurveP384, tls.CurveP256},
    PreferServerCipherSuites: true,
    CipherSuites: []uint16{
      tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
      tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
      tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
      tls.TLS_RSA_WITH_AES_256_CBC_SHA,
    },
  }
  srv := &http.Server{
    ReadHeaderTimeout: 2 * time.Second,
    Addr:              defaultServerDomain,
    Handler:           mux,
    TLSConfig:         cfg,
    TLSNextProto:      make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0),
  }
  log.Fatal(srv.ListenAndServeTLS(certPemPath, privKeyPath))
}

客户端代码:

package main

import (
  "crypto/tls"
  "crypto/x509"
  "fmt"
  "io"
  "log"
  "net/http"
  "os"
  "time"
)

const (
  serverDomain = "https://localhost:443/demo/echo"
  certPemPath  = "./selfsigned.crt"
)

func main() {

  cert, err := os.ReadFile(certPemPath)
  if err != nil {
    log.Fatal(err)
  }
  certPool := x509.NewCertPool()
  if ok := certPool.AppendCertsFromPEM(cert); !ok {
    log.Fatalf("unable to parse cert from %s", certPemPath)
  }

  client := &http.Client{
    Timeout: 2 * time.Second,
    Transport: &http.Transport{
      DisableKeepAlives:  false,
      TLSClientConfig: &tls.Config{
        RootCAs: certPool,
      },
    },
  }

  r, err := http.NewRequest("GET", serverDomain, nil)
  req, err := client.Do(r)
  if err != nil {
    log.Fatal(err)
  }
  req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.7113.93 Safari/537.36")
  defer req.Body.Close()

  html, err := io.ReadAll(req.Body)
  if err != nil {
    log.Fatal(err)
  }
  fmt.Printf("%v\n", req.Status)
  fmt.Printf(string(html))
}

假设获取服务器端:

UserAgent:Mozilla/5.0(Windows NT 10.0;Win64;x64;rv:91.0)Gecko/20100101 Firefox/91.0 Waterfox/91.4.2

相反,我得到了这个:

用户代理:Go-http-client/1.1

但是当我在我的例子中使用 Waterfox 浏览器时,它就可以工作了

UserAgent:Mozilla/5.0(Windows NT 10.0;Win64;x64;rv:91.0)Gecko/20100101 Firefox/91.0 Waterfox/91.4.2

这与我使用的 selfsinged 证书的代码或证书有关吗

最佳答案

我认为问题很可能在这里:

r, err := http.NewRequest("GET", serverDomain, nil)
req, err := client.Do(r)

NewRequest 的定义是 func NewRequest(method, url string, body io.Reader) (*Request, error) 和 Client.Do func (c *Client) Do(req *Request) (*Response, error)。所以上面的代码可能更容易理解为:

req, err := http.NewRequest("GET", serverDomain, nil)
resp, err := client.Do(req) // This returns a response; not  the request

当您调用 Do 时,就会发出请求(因此必须在此之前设置 header )。当您设置要调用 resp.Header.Set... 的 header 时,对您的代码进行上述改写(即您正在更改请求返回的 header ;而不是请求 header )。

在调用 Do 之前更改代码以设置 header ,即

req, err := http.NewRequest("GET", serverDomain, nil)
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.7113.93 Safari/537.36")
resp, err := client.Do(req)

注意:我尚未完整测试您的代码,因此可能存在其他问题

关于go - Http Over TLS Golang 未接收 header ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72598797/

相关文章:

go - 比较命名管道和未命名类型时编译错误

Go libstd.so 在 Alpine 上出现错误

go - 如何使用gorm从数据库中删除项目范围

oracle - 尝试在 Linux/Ubuntu 上使用 oracle 库构建静态 CGO 可执行文件

python - 如何在 python ssl 中获取 TLS 客户端支持的 TLS 版本

jQuery 加载无效的安全证书错误

azure - Azure Web 应用程序中某些 URL 的 TLS 1.0

gradle - 有没有办法强制 gradle 只使用 https 连接?

javascript - 在没有服务器的情况下使用 Google Cloud Messaging 发送通知

wordpress - www.example.com 不重定向到 HTTPS