Go语言标准库内建提供了net/http包,涵盖了HTTP客户端和服务端的具体实现。使用net/http包,我们可以很方便地编写HTTP客户端或服务端的程序。

http服务端的创建流程

在使用http/net包创建服务端只需要两个步骤 绑定处理器函数 func(ResponseWriter, *Request)与 启用监听 http.ListenAndServe

go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
package main

import "net/http"

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("123"))
	})
	http.ListenAndServe(":8080", nil)
}

通过分析net/http包中server.go 在执行创建http服务端主要执行了下面几个步骤:

  • http.HandleFunc 绑定处理函数
  • 所有的操作的方法都属于一个结构体 ServeMux
    • m: 用户传入的路由和处理方法的映射表,路由和处理函数被定义为结构体muxEntry的属性
    • mu: 实例化出来的对象的读写锁
  • 调用DefaultServeMux.Handle()
  • DefaultServeMux.Handle()中调用DefaultServeMux.HandleFunc(pattern, handler)
  • 在将传入http.HandleFunc()的回调函数,与路由的映射信息,放到该DefaultServeMux的属性中 映射map中 muxEntry
  • http.ListenAndServe 启动服务监听
  • 实例化一个server结构体
  • 调用 ListenAndServe()
  • ListenAndServe()net.Listen("tcp", addr) 启动tcp服务监听
  • Serve()中 appcet()处理用户连接,go c.serve(connCtx) 处理业务段(如判断信息,拼接http、找到对应处理函数)

综上所述,net/http server.go 一切的基础为ServeMux 和 Handler

Go语言的net/http包还封装了常用处理器,如 FileServerNotFoundHandler RedirectHandler

http客户端的使用

简单的Get请求

go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
	"bytes"
	"fmt"
	"net/http"
	"reflect"
)

func main() {
	resp, err := http.Get("http://www.baidu.com")

	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(reflect.TypeOf(resp.Body)) // *http.gzipReader
	b := bytes.NewBuffer(make([]byte, 1024))
	b.ReadFrom(resp.Body)
	fmt.Println(string(b.Bytes()))
}

post请求

go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
	"net/http"
	"fmt"
	"io/ioutil"
	"net/url"
)

func main() {

	postParam := url.Values{
		"user":      {"xxxxxx"},
		"Pwd": {"1"},
	}

	resp, err := http.PostForm("http://www.baidu.com/loginRegister/login", postParam)
	if err != nil {
		fmt.Println(err)
		return
	}

	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Println(string(body))
}

构建客户端请求

go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
  "fmt"
  "net/http"
  "io/ioutil"
)

func main() {

  url := "http://10.0.0.3:5555/v2/services/haproxy/configuration/version"
  method := "GET"

  client := &http.Client {
  }
  req, err := http.NewRequest(method, url, nil)

  if err != nil {
    fmt.Println(err)
  }

  res, err := client.Do(req)
  defer res.Body.Close()
  body, err := ioutil.ReadAll(res.Body)

  fmt.Println(string(body))
}

使用认证

go
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
func basicAuth(username, password string) string {
  auth := username + ":" + password
  return base64.StdEncoding.EncodeToString([]byte(auth))
}

func redirectPolicyFunc(req *http.Request, via []*http.Request) error{
  req.Header.Add("Authorization","Basic " + basicAuth("username1","password123"))
  return nil
}

func main() {
  client := &http.Client{
    Jar: cookieJar,
    CheckRedirect: redirectPolicyFunc,
  }

  req, err := http.NewRequest("GET", "http://localhost/", nil)
  req.Header.Add("Authorization","Basic " + basicAuth("username1","password123")) 
  resp, err := client.Do(req)
}

Reference

Basic HTTP Auth in Go