net/http
一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)請(qǐng)求
func helloWorld(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello world"))
}
func main() {
http.HandleFunc("/hello", helloWorld)
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal(err)
}
}
請(qǐng)求http://localhost:8080/hello會(huì)打印hello world
go web的請(qǐng)求流程
go10.1的源碼
func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
if fn := testHookServerServe; fn != nil {
fn(srv, l)
}
var tempDelay time.Duration // how long to sleep on accept failure
if err := srv.setupHTTP2_Serve(); err != nil {
return err
}
srv.trackListener(l, true)
defer srv.trackListener(l, false)
baseCtx := context.Background() // base is always background, per Issue 16220
ctx := context.WithValue(baseCtx, ServerContextKey, srv)
for {
rw, e := l.Accept()
if e != nil {
select {
case <-srv.getDoneChan():
return ErrServerClosed
default:
}
if ne, ok := e.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
return e
}
tempDelay = 0
c := srv.newConn(rw)
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve(ctx)
}
}
go c.serve()這里我們可以看到客戶端的每次請(qǐng)求都會(huì)創(chuàng)建一個(gè)Conn懦冰,這個(gè)Conn里面保存了該次請(qǐng)求的信息贞岭,然后再傳遞到對(duì)應(yīng)的handler懈凹,該handler中便可以讀取到相應(yīng)的header信息齿诉,這樣保證了每個(gè)請(qǐng)求的獨(dú)立性。
路由器結(jié)構(gòu)
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
es []muxEntry // slice of entries sorted from longest to shortest.
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
h Handler
pattern string
}
type Handler interface {
ServeHTTP(ResponseWriter, *Request) // 路由實(shí)現(xiàn)器
}
Handler是一個(gè)接口芭概,但是前一小節(jié)中的sayhelloName函數(shù)并沒有實(shí)現(xiàn)ServeHTTP這個(gè)接口,為什么能添加呢?原來(lái)在http包里面還定義了一個(gè)類型HandlerFunc,我們定義的函數(shù)sayhelloName就是這個(gè)HandlerFunc調(diào)用之后的結(jié)果耙饰,這個(gè)類型默認(rèn)就實(shí)現(xiàn)了ServeHTTP這個(gè)接口,即我們調(diào)用了HandlerFunc(f),強(qiáng)制類型轉(zhuǎn)換f成為HandlerFunc類型纹份,這樣f就擁有了ServeHTTP方法苟跪。
GET請(qǐng)求
import (
"fmt"
"io/ioutil"
"net/http"
)
func main() {
resp, err := http.Get("http://httpbin.org/ip")
if err != nil {
fmt.Errorf("%s", err.Error())
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Errorf("%s", err.Error())
return
}
fmt.Println(string(body))
}
自定義request請(qǐng)求
func main() {
query := map[string]string{"location": "北京",
"ak": "VAuehGLIw7lW6ovwpnKboM3I", "output": "json"}
u, _ := url.Parse("http://api.map.baidu.com/telematics/v3/weather")
q := u.Query()
for k, v := range query {
q.Set(k, v)
}
u.RawQuery = q.Encode()
req, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
fmt.Errorf("%s", err.Error())
return
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Errorf("%s", err.Error())
return
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Errorf("%s", err.Error())
return
}
fmt.Println(string(body))
}
Post請(qǐng)求
func main() {
url := "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule"
payload := strings.NewReader("doctype=json&i=好好學(xué)習(xí) 天天向上")
req, err := http.NewRequest("POST", url, payload)
if err != nil {
fmt.Errorf("%s", err.Error())
return
}
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Errorf("%s", err.Error())
return
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Errorf("%s", err.Error())
return
}
fmt.Println(string(body))
}
fasthttp
http Get請(qǐng)求
import (
"fmt"
"github.com/valyala/fasthttp"
"log"
)
func main() {
c := fasthttp.Client{}
statusCode, body, err := c.Get(nil, "http://httpbin.org/ip")
if statusCode == fasthttp.StatusOK {
fmt.Println(string(body))
} else {
log.Fatalf("%d:%s", statusCode, err.Error())
}
}