在构建web应用时,我们经常需要处理HTTP请求、做网页抓取或者搭建web服务器等任务,而Go语言在这方面为我们提供了强大的内置工具:net/http标准库,它为我们操作和处理HTTP协议提供了便利。

基础用法

一:处理HTTP请求

首先,我们来看看如何使用net/http标准库发送一个HTTP请求。net/http库中的http.Get函数可以快速地对一个URL发起GET请求。

  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "log"
  6. "net/http"
  7. )
  8. func main() {
  9. res, err := http.Get("http://example.com/")
  10. if err != nil {
  11. log.Fatal(err)
  12. }
  13. defer res.Body.Close()
  14. body, err := ioutil.ReadAll(res.Body)
  15. if err != nil {
  16. log.Fatal(err)
  17. }
  18. fmt.Printf("%s", body)
  19. }

二:创建和启动HTTP服务器

在Go语言中,我们可以使用http.ListenAndServe函数配合http.HandleFunc函数快速地创建一个HTTP服务器。

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. )
  6. func helloHandler(w http.ResponseWriter, r *http.Request) {
  7. fmt.Fprintf(w, "Hello, Gopher!")
  8. }
  9. func main() {
  10. http.HandleFunc("/hello", helloHandler)
  11. if err := http.ListenAndServe(":8080", nil); err != nil {
  12. log.Fatal(err)
  13. }
  14. }

三:使用http.Client自定义请求行为

有时,我们需要对HTTP请求进行更细粒度的控制,比如设置超时时间、添加请求头等等。

这个时候,我们可以使用http.Clienthttp.Request来自定义我们的请求行为。

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. "time"
  6. )
  7. func main() {
  8. client := http.Client{
  9. Timeout: 5 * time.Second,
  10. }
  11. req, err := http.NewRequest("GET", "http://example.com", nil)
  12. if err != nil {
  13. log.Fatal(err)
  14. }
  15. req.Header.Add("User-Agent", "myClient")
  16. resp, err := client.Do(req)
  17. if err != nil {
  18. log.Fatal(err)
  19. }
  20. defer resp.Body.Close()
  21. fmt.Printf("Response status: %s\n", resp.Status)
  22. }

以上,我们简洁明了地介绍了如何使用Golang中的net/http标准库进行HTTP请求的发送、服务器的创建以及请求行为的自定义。但是,net/http库的功能远不止这些。

进阶用法

反向代理

反向代理是一个非常常见的需求,Golang的net/http库能简单地帮我们实现这一功能。

  1. package main
  2. import (
  3. "log"
  4. "net/http"
  5. "net/http/httputil"
  6. "net/url"
  7. )
  8. func main() {
  9. targetUrl, _ := url.Parse("http://example.com")
  10. proxy := httputil.NewSingleHostReverseProxy(targetUrl)
  11. http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  12. proxy.ServeHTTP(w, r)
  13. })
  14. log.Fatal(http.ListenAndServe(":8080", nil))
  15. }

在上述代码中,我们通过httputil.NewSingleHostReverseProxy函数创建了一个反向代理处理器,然后在http处理函数中通过这个处理器来处理进来的http请求。

升级websocket

WebSocket提供了在单个 TCP 连接上进行全双工通信的能力。在Golang中,我们可以借助golang.org/x/net/websocket包(这不是标准库,但是是官方维护的包)轻松实现WebSocket。

  1. package main
  2. import (
  3. "fmt"
  4. "golang.org/x/net/websocket"
  5. "net/http"
  6. )
  7. func Echo(ws *websocket.Conn) {
  8. var err error
  9. for {
  10. var reply string
  11. if err = websocket.Message.Receive(ws, &reply); err != nil {
  12. fmt.Println("Can't receive")
  13. break
  14. }
  15. fmt.Println("Received back from client: " + reply)
  16. msg := "Received: " + reply
  17. fmt.Println("Sending to client: " + msg)
  18. if err = websocket.Message.Send(ws, msg); err != nil {
  19. fmt.Println("Can't send")
  20. break
  21. }
  22. }
  23. }
  24. func main() {
  25. http.Handle("/", websocket.Handler(Echo))
  26. if err := http.ListenAndServe(":1234", nil); err != nil {
  27. log.Fatal("ListenAndServe:", err)
  28. }
  29. }

在上面的例子中,我们创建了一个简单的回音服务,客户端发送一个消息到服务器,服务器会追加一个”Received: “前缀并发送回去。

需要注意的是,WebSocket 只能用于已具有兼容 WebSocket 的客户端(如一些现代 web 浏览器)的 HTTP 服务器。websocket包并不能用于一个普通的HTTP服务端。

当然,除了反向代理和Websocket, net/http包中还有诸多高级的使用方法。这里,我会介绍两个常见的高级应用场景:使用http.RoundTripper自定义HTTP请求过程和使用http.CookieJar接口处理Cookie。

自定义HTTP请求过程

如果你需要在发送HTTP请求时进行更多的自定义控制,如自定义DNS解析、TCP连接过程、TLS握手等等,那么你可以通过实现 http.RoundTripper 接口来满足需求。

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. nethttp "net/http" // alias to avoid conflict
  6. "time"
  7. )
  8. type myTransport struct {
  9. transportation http.RoundTripper
  10. }
  11. func (t *myTransport) RoundTrip(req *http.Request) (*http.Response, error) {
  12. req.Header.Add("User-Agent", "myClient")
  13. resp, err := t.transportation.RoundTrip(req)
  14. if err != nil {
  15. return nil, err
  16. }
  17. // you can access Response here
  18. fmt.Println("Status:", resp.Status)
  19. return resp, nil
  20. }
  21. func main() {
  22. t := &myTransport{
  23. transportation: nethttp.DefaultTransport,
  24. }
  25. client := &http.Client{Transport: t}
  26. resp, err := client.Get("http://example.com")
  27. if err != nil {
  28. log.Fatal(err)
  29. }
  30. defer resp.Body.Close()
  31. fmt.Println("Response Status:", resp.Status)
  32. }

在上述代码中,我们实现了自己的 http.RoundTripper 接口,在每次发送HTTP请求时,添加了自定义的User-Agent头,并在请求返回后打印了响应的状态码。

处理Cookie

http.CookieJar 是一个接口,可以用来自定义HTTP请求中的cookie处理逻辑。Go标准库为我们提供了一个简单的内存CookieJar的实现 net/http/cookiejar

  1. package main
  2. import (
  3. "net/http"
  4. "net/http/cookiejar"
  5. "net/url"
  6. )
  7. func main() {
  8. jar, err := cookiejar.New(nil)
  9. if err != nil {
  10. log.Fatal(err)
  11. }
  12. client := &http.Client{
  13. Jar: jar,
  14. }
  15. // Create a cookie on client side
  16. client.Jar.SetCookies(
  17. &url.URL{Scheme: "http", Host: "example.com"},
  18. []*http.Cookie{{Name: "cookieName", Value: "cookieValue"}},
  19. )
  20. // Check if the cookie has been set
  21. if cookies := client.Jar.Cookies(&url.URL{Scheme: "http", Host: "example.com"}); len(cookies) > 0 {
  22. fmt.Println("Cookie:", cookies[0])
  23. }
  24. }

在上述例子中,我们首先创建了一个新的CookieJar实例,并将其用于一个新的HTTP客户端中。然后,我们在客户端上创建了一个新的cookie,并检查它是否已经被存储在了CookieJar中。

如果这篇文章帮助了你,不妨一键三连哦?