hello world

  1. package main
  2. import (
  3. "log"
  4. "net/http"
  5. )
  6. func main() {
  7. http.HandleFunc("/v1/hello", func(writer http.ResponseWriter, request *http.Request) {
  8. writer.Write([]byte("hello http\n"))
  9. })
  10. log.Fatal(http.ListenAndServe(":8090",nil))
  11. }

启动当前服务

  1. curl -X GET 'http://localhost:8090/v1/hello'
  2. hello http

ServeHTTP

  1. type BaseHander struct {
  2. }
  3. func (hander *BaseHander)ServeHTTP(resp http.ResponseWriter,req *http.Request){
  4. fmt.Println("url path=>",req.URL.Path)
  5. fmt.Println("url param a =>",req.URL.Query().Get("a"))
  6. resp.Write([]byte("hello world"))
  7. }
  8. func main() {
  9. http.ListenAndServe(":8080",&BaseHander{});
  10. }

muxHandler 路由

  1. type ServeMux struct {
  2. mu sync.RWMutex
  3. m map[string]muxEntry
  4. es []muxEntry // slice of entries sorted from longest to shortest.
  5. hosts bool // whether any patterns contain hostnames
  6. }
  7. type muxEntry struct {
  8. h Handler
  9. pattern string
  10. }
  11. type Handler interface {
  12. ServeHTTP(ResponseWriter, *Request) // 路由实现器
  13. }

Handler是一个接口,但是前一小节中的sayhelloName函数并没有实现ServeHTTP这个接口,为什么能添加呢?原来在http包里面还定义了一个类型HandlerFunc,我们定义的函数sayhelloName就是这个HandlerFunc调用之后的结果,这个类型默认就实现了ServeHTTP这个接口,即我们调用了HandlerFunc(f),强制类型转换f成为HandlerFunc类型,这样f就拥有了ServeHTTP方法。

  1. package mux
  2. import (
  3. "net/http"
  4. )
  5. type muxHandler struct {
  6. handlers map[string]http.Handler
  7. handleFuncs map[string]func(resp http.ResponseWriter, req *http.Request)
  8. }
  9. func NewMuxHandler() *muxHandler {
  10. return &muxHandler{
  11. make(map[string]http.Handler),
  12. make(map[string]func(resp http.ResponseWriter, req *http.Request)),
  13. }
  14. }
  15. func (handler *muxHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
  16. urlPath := req.URL.Path
  17. if hl, ok := handler.handlers[urlPath]; ok {
  18. hl.ServeHTTP(resp, req)
  19. return
  20. }
  21. if fn, ok := handler.handleFuncs[urlPath]; ok {
  22. fn(resp, req)
  23. return
  24. }
  25. http.NotFound(resp, req)
  26. }
  27. func (hander *muxHandler) Handle(pattern string, hl http.Handler) {
  28. hander.handlers[pattern] = hl
  29. }
  30. func (handler *muxHandler) HandleFunc(pattern string, fn func(resp http.ResponseWriter, req *http.Request)) {
  31. handler.handleFuncs[pattern] = fn
  32. }
  1. var (
  2. port string
  3. )
  4. func main() {
  5. flag.StringVar(&port, "port", ":8080", "port to listen")
  6. flag.Parse()
  7. router :=mux.NewMuxHandler()
  8. router.Handle("/hello/golang/", &BaseHander{})
  9. router.HandleFunc("/hello/world", func(resp http.ResponseWriter, req *http.Request) {
  10. resp.Write([]byte("hello world"))
  11. })
  12. http.ListenAndServe(port, router)
  13. }

go web的请求流程

Go包——net/http - 图1
go10.1的源码

  1. func (srv *Server) Serve(l net.Listener) error {
  2. defer l.Close()
  3. if fn := testHookServerServe; fn != nil {
  4. fn(srv, l)
  5. }
  6. var tempDelay time.Duration // how long to sleep on accept failure
  7. if err := srv.setupHTTP2_Serve(); err != nil {
  8. return err
  9. }
  10. srv.trackListener(l, true)
  11. defer srv.trackListener(l, false)
  12. baseCtx := context.Background() // base is always background, per Issue 16220
  13. ctx := context.WithValue(baseCtx, ServerContextKey, srv)
  14. for {
  15. rw, e := l.Accept()
  16. if e != nil {
  17. select {
  18. case <-srv.getDoneChan():
  19. return ErrServerClosed
  20. default:
  21. }
  22. if ne, ok := e.(net.Error); ok && ne.Temporary() {
  23. if tempDelay == 0 {
  24. tempDelay = 5 * time.Millisecond
  25. } else {
  26. tempDelay *= 2
  27. }
  28. if max := 1 * time.Second; tempDelay > max {
  29. tempDelay = max
  30. }
  31. srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
  32. time.Sleep(tempDelay)
  33. continue
  34. }
  35. return e
  36. }
  37. tempDelay = 0
  38. c := srv.newConn(rw)
  39. c.setState(c.rwc, StateNew) // before Serve can return
  40. go c.serve(ctx)
  41. }
  42. }

go c.serve()这里我们可以看到客户端的每次请求都会创建一个Conn,这个Conn里面保存了该次请求的信息,然后再传递到对应的handler,该handler中便可以读取到相应的header信息,这样保证了每个请求的独立性。

参考

https://github.com/ma6174/blog/issues/11
https://www.cnblogs.com/itbsl/p/12175645.html