Http Over TLS Golang 未接收到头部信息

huangapple go评论81阅读模式
英文:

Http Over TLS Golang Not Receiving Headers

问题

我从客户端发送了"User-Agent 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

但实际上我得到的是:

UserAgent : 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

这是代码还是我使用的自签名证书的问题?

英文:

I am sending 'User-Agent Header' from my client but not receiving on server-side but when i use browser it works.

server code :

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))
}

client code :

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))
}

Suppose to get server-side :

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

Instead i get this :

UserAgent : Go-http-client/1.1

But when i use browser in my case waterfox then it works i get

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

Is it something to do with code or certificate i am using selfsinged certificate

答案1

得分: 1

我认为问题最有可能出在这里:

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) // 这里返回的是响应,而不是请求

当你调用 Do 方法时,请求会被发送(所以在这之前必须设置好请求头)。根据上面重新表述的代码,当你设置请求头时,应该调用 resp.Header.Set...(也就是你在修改请求返回的响应头,而不是请求头)。

将你的代码修改为在调用 Do 之前设置请求头,即:

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)

注意:我没有完整测试过你的代码,所以可能还有其他问题。

英文:

I believe that the issue is most likely here:

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

The definition for NewRequest is func NewRequest(method, url string, body io.Reader) (*Request, error) and Client.Do func (c *Client) Do(req *Request) (*Response, error). So the code above is probably easier understood as:

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

When you call Do the request is made (so the headers must be set before that point). Taking the above rephrasing of your code when you set the headers you would be calling resp.Header.Set... (i.e. you are changing the headers returned by the request; not the request headers).

Change your code to set the headers before calling Do i.e.

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)

Note: I have not tested your code in full so there may be other issues

huangapple
  • 本文由 发表于 2022年6月13日 14:57:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/72598797.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定