golang如何将http请求流转到gin

gin是作为golang web开发中被广泛使用到的框架,了解其内部的实现有助于我们更好地理解gin的设计思想。

这篇文章主要探讨两个问题。

  • http请求如何流转到gin
  • gin为什么比golang的http路由寻找更快

开始之前我们先来看看分别用golang原生的http包实现一个http服务和使用gin实现的代码,先看看原生http包实现的http服务

package main


import (
  "net/http"
)


func main() {
   
  http.HandleFunc("/ping", func(writer http.ResponseWriter, request *http.Request) {
   
    writer.Write([]byte(`{"message":"ok"}`))
  })
  http.ListenAndServe(":9090", nil)
}

这段代码做了两件事情,注册路由、启动服务监听9090端口。接下来我们对这段代码进一步分析,在第8行的地方是将路由/ping和对应的处理函数注册到http服务中,我们进入http.HandleFunc()函数看看该函数做了什么事情。

// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
   
  DefaultServeMux.HandleFunc(pattern, handler)
}

将路由和处理函数注册到了DefaultServeMux中,所以我们先看看DefaultServeMux的结构是什么。

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
}


// NewServeMux allocates and returns a new ServeMux.
func NewServeMux() *ServeMux {
    return new(ServeMux) }


// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = &defaultServeMux


var defaultServeMux ServeMux

第17行代码就是刚刚用来注册http路由的服务,通过第19行代码知道了他是一个ServeMux类型。知道了DefaultServeMux的类型我们接着看具体的实现代码。

// HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
   
  if handler == nil {
   
    panic("http: nil handler")
  }
  mux.Handle(pattern, HandlerFunc(handler))
}


// Handle registers the handler for the given pattern.
// If a handler already exists for pattern, Handle panics.
func (mux *ServeMux) Handle(pattern string, handler Handler) {
   
  mux.mu.Lock()
  defer mux.mu.Unlock()


  if pattern == "" {
   
    panic("http: invalid pattern")
  }
  if handler == nil {
   
    panic("http: nil handler")
  }
  if _, exist := mux.m[pattern]; exist {
   
    panic("http: multiple registrations for " + pattern)
  }


  if mux.m == nil {
   
    mux.m = make(map[string]muxEntry)
  }
  e := muxEntry{
   h: handler, pattern: pattern}
  mux.m[pattern] = e
  if pattern[len(pattern)-1] == '/' {
   
    mux.es = appendSorted(mux.es, e)
  }


  if pattern[0] != '/' {
   
    mux.hosts = true
  }
}

主要的代码就是第29行,这里将路由和处理函数保存在了ServeMux的m中,通过前面的代码我们知道m是一个map,到这里路由注册的过程就分析完了。接下来我们来看看 http.ListenAndServe()做了什么事情。

// ListenAndServe listens on the TCP network address srv.Addr and then
// calls Serve to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
//
// If srv.Addr is blank, ":http" is used.
//
// ListenAndServe always returns a non-nil error. After Shutdown or Close,
// the returned error is ErrServerClosed.
func (srv *Server) ListenAndServe() error {
   
  if srv.shuttingDown() {
   
    return ErrServerClosed
  }
  addr := srv.Addr
  if addr == "" {
   
    addr = ":http"
  }
  ln, err := net.Listen("tcp", addr)
  if err != nil {
   
    return err
  }
  return srv.Serve(ln)
}

第22行就是真正开始启动http服务,并接受请求的函数。第17行创建了主动套接字并监听套接字,接着我们进入Serve()函数。

func (srv *Server) Serve(l net.Listener) error {
   
  if fn := testHookServerServe; fn != nil {
   
    fn(srv, l) // call hook with unwrapped listener
  }


  origListener := l
  l = &onceCloseListener{
   Listener: l}
  defer l.Close()


  if err := srv.setupHTTP2_Serve(); err != nil {
   
    return err
  }


  if !srv.trackListener(&l, true) {
   
    return ErrServerClosed
  }
  defer srv.trackListener(&l, false)


  baseCtx := context.Background()
  if srv.BaseContext != nil {
   
    baseCtx = srv.BaseContext(origListener)
    if baseCtx == nil {
   
      panic("BaseContext returned a nil context")
    }
  }


  var tempDelay time.Duration // how long to sleep on accept failure


  ctx := context.WithValue(baseCtx, ServerContextKey, srv)
  for {
   
    rw, err 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值