RouterGroup、Handlers、goroutine并发
// 运行在debug模式
gin.SetMode(gin.DebugMode)
{
switch value {
case DebugMode, "":
ginMode = debugCode
case ReleaseMode:
ginMode = releaseCode
case TestMode:
ginMode = testCode
default:
panic("gin mode unknown: " + value)
}
if value == "" {
value = DebugMode
}
modeName = value
}
// 创建路由,没有任何中间件 Creates a router without any middleware by default
var engine *Engine = gin.New()
{
debugPrintWARNINGNew()
{
debugPrint(`[WARNING] Running in "debug" mode. Switch to "release" mode in production.
- using env: export GIN_MODE=release
- using code: gin.SetMode(gin.ReleaseMode)
`)
}
engine := &gin.Engine{
//type RouterGroup struct {
// Handlers HandlersChain
// basePath string
// engine *Engine // 对engine的依赖
// root bool
//}
// 创建 RouterGroup
RouterGroup: RouterGroup{
Handlers: nil, // 处理器链
basePath: "/",
root: true, // 是根路由
},
// 模版函数
FuncMap: template.FuncMap{},
RedirectTrailingSlash: true,
RedirectFixedPath: false,
HandleMethodNotAllowed: false,
ForwardedByClientIP: true,
AppEngine: defaultAppEngine,
UseRawPath: false,
UnescapePathValues: true,
MaxMultipartMemory: defaultMultipartMemory, // 最大Multipart内存数 defaultMultipartMemory = 32 << 20
//type methodTree struct {
// method string
// root *node
//}
//type methodTrees []methodTree
trees: make(methodTrees, 0, 9),
// 渲染引擎分割符
delims: render.Delims{Left: "{{", Right: "}}"},
secureJsonPrefix: "while(1);",
}
engine.RouterGroup.engine = engine // 对engine的引用
engine.pool.New = func() interface{} { // 创建
return engine.allocateContext()
}
return engine
}
// 文件上传最大的空间
// Set a lower memory limit for multipart forms (default is 32 MiB)
engine.MaxMultipartMemory = int64(3) << 20 // 3 MiB 上传的图片最大允许的大小,3MB
// 中间件 设置到默认的 RouterGroup.Handlers ,没有路由
{
// 全局中间件,日志记录器, Global middleware
// Logger middleware will write the logs to gin.DefaultWriter even if you set with GIN_MODE=release.
// By default gin.DefaultWriter = os.Stdout
engine.Use(gin.Logger())
{
engine.RouterGroup.Use(middleware...)
{
// group === RouterGroup
// append 中间件
group.Handlers = append(group.Handlers, middleware...)
// group === RouterGroup
return group.returnObj()
{
if group.root {
return group.engine
}
return group
}
}
engine.rebuild404Handlers()
{
engine.allNoRoute = engine.combineHandlers(engine.noRoute)
}
engine.rebuild405Handlers()
{
engine.allNoMethod = engine.combineHandlers(engine.noMethod)
}
return engine
}
// 中间件,错误处理。Recovery middleware recovers from any panics and writes a 500 if there was one.
engine.Use(gin.Recovery())
// 中间件 - api统计
engine.Use(middleware.APIStatsD())
}
// 路由
{
//路由写法:
// 1、必须以“/”开头
// 2、路由中要参数,只要参数前有“*”或“:”即可
//"/module0/ctrl0/action0/:param0/:param1/*"
frontApi := engine.Group("/api", middleware.RefreshTokenCookie) // 创建一个新的 RouterGroup,并设置一个名为“middleware.RefreshTokenCookie”的handler
{
// 创建新的RouterGroup
return &gin.RouterGroup{
// 把根 group 的 handlers 拷贝出来,并进行合并
Handlers: group.combineHandlers(handlers){
finalSize := len(group.Handlers) + len(handlers)
if finalSize >= int(abortIndex) {
panic("too many handlers")
}
mergedHandlers := make(HandlersChain, finalSize)
copy(mergedHandlers, group.Handlers)
copy(mergedHandlers[len(group.Handlers):], handlers)
return mergedHandlers
}, // handlers === middleware.RefreshTokenCookie
// 添加相对路径
basePath: group.calculateAbsolutePath(relativePath), // relativePath === "/api"
{
// return "/api"
return joinPaths(group.basePath, relativePath)
}
// 对engine的引用
engine: group.engine,
}
}
// 添加路由
frontApi.GET("/siteinfo", common.SiteInfo) // 访问地址为 “/api/siteinfo” 等价 engine.addRoute("GET","/api/siteinfo", common.SiteInfo0, common.SiteInfo1)
{
return group.handle("GET", relativePath, handlers)
{
absolutePath := group.calculateAbsolutePath(relativePath)
{
//return "/api/siteinfo"
return joinPaths(group.basePath, relativePath)
}
// 把上级 group 的 handlers 拷贝出来,并进行合并
handlers = group.combineHandlers(handlers)
{
finalSize := len(group.Handlers) + len(handlers)
if finalSize >= int(abortIndex) {
panic("too many handlers")
}
mergedHandlers := make(HandlersChain, finalSize)
copy(mergedHandlers, group.Handlers)
copy(mergedHandlers[len(group.Handlers):], handlers)
return mergedHandlers
}
group.engine.addRoute(httpMethod, absolutePath, handlers)
{
// httpMethod === "GET"
// absolutePath === "/api/siteinfo"
// handlers === 处理器列表
assert1(path[0] == '/', "path must begin with '/'")
assert1(method != "", "HTTP method can not be empty")
assert1(len(handlers) > 0, "there must be at least one handler")
debugPrintRoute(method, path, handlers)
{
if IsDebugging() {
nuHandlers := len(handlers)
handlerName := nameOfFunction(handlers.Last())
debugPrint("%-6s %-25s --> %s (%d handlers)\n", httpMethod, absolutePath, handlerName, nuHandlers)
}
}
// 按请求方式method归类
root := engine.trees.get(method)
if root == nil {
//type node struct {
// path string
// indices string
// children []*node
// handlers HandlersChain
// priority uint32
// nType nodeType
// maxParams uint8
// wildChild bool
//}
//type methodTree struct {
// method string
// root *node
//}
root = new(node)
engine.trees = append(engine.trees, methodTree{method: method, root: root})
}
// 添加路由 root === node(type node struct)
root.addRoute(path, handlers)
{
fullPath := path
n.priority++
// 计算"参数"数量
numParams := countParams(path)
{
var n uint
for i := 0; i < len(path); i++ {
if path[i] != ':' && path[i] != '*' {
continue
}
n++
}
if n >= 255 {
return 255
}
return uint8(n)
}
// non-empty tree
if len(n.path) > 0 || len(n.children) > 0 { // !!!!!不是空树!!!!!
walk:
for {
// Update maxParams of the current node
if numParams > n.maxParams {
n.maxParams = numParams
}
// Find the longest common prefix.
// This also implies that the common prefix contains no ':' or '*'
// since the existing key can't contain those chars.
i := 0
max := min(len(path), len(n.path))
for i < max && path[i] == n.path[i] {
i++
}
// Split edge
if i < len(n.path) { // "新地址"比"已有的地址"短,那么提升为父级节点
child := node{
path: n.path[i:],
wildChild: n.wildChild,
indices: n.indices,
children: n.children,
handlers: n.handlers,
priority: n.priority - 1,
}
// Update maxParams (max of all children)
for i := range child.children {
if child.children[i].maxParams > child.maxParams {
child.maxParams = child.children[i].maxParams
}
}
n.children = []*node{&child}
// []byte for proper unicode char conversion, see #65
n.indices = string([]byte{n.path[i]})
n.path = path[:i]
n.handlers = nil
n.wildChild = false
}
// Make new node a child of this node
if i < len(path) { // 作为子节点加入
path = path[i:]
if n.wildChild {
n = n.children[0]
n.priority++
// Update maxParams of the child node
if numParams > n.maxParams {
n.maxParams = numParams
}
numParams--
// Check if the wildcard matches
if len(path) >= len(n.path) && n.path == path[:len(n.path)] {
// check for longer wildcard, e.g. :name and :names
if len(n.path) >= len(path) || path[len(n.path)] == '/' {
continue walk
}
}
panic("path segment '" + path +
"' conflicts with existing wildcard '" + n.path +
"' in path '" + fullPath + "'")
}
c := path[0]
// slash after param
if n.nType == param && c == '/' && len(n.children) == 1 {
n = n.children[0]
n.priority++
continue walk
}
// Check if a child with the next path byte exists
for i := 0; i < len(n.indices); i++ {
if c == n.indices[i] {
i = n.incrementChildPrio(i)
n = n.children[i]
continue walk
}
}
// Otherwise insert it
if c != ':' && c != '*' {
// []byte for proper unicode char conversion, see #65
n.indices += string([]byte{c})
child := &node{
maxParams: numParams,
}
n.children = append(n.children, child)
n.incrementChildPrio(len(n.indices) - 1)
n = child
}
n.insertChild(numParams, path, fullPath, handlers)
{
// 作为子节点加入 ...
}
return
} else if i == len(path) { // Make node a (in-path) leaf
if n.handlers != nil {
panic("handlers are already registered for path ''" + fullPath + "'")
}
n.handlers = handlers
}
return
}
} else { // Empty tree !!!!!空树!!!!!
// numParams === 地址参数数量
// path === "/api/siteinfo"
// fullPath === "/api/siteinfo"
// handlers === 处理器列表
n.insertChild(numParams, path, fullPath, handlers)
{
var offset int // already handled bytes of the path
// numParams === 地址参数数量
// find prefix until first wildcard (beginning with ':'' or '*'')
for i, max := 0, len(path); numParams > 0; i++ {
c := path[i]
if c != ':' && c != '*' {
continue
}
// find wildcard end (either '/' or path end)
end := i + 1
for end < max && path[end] != '/' {
switch path[end] {
// the wildcard name must not contain ':' and '*'
case ':', '*':
panic("only one wildcard per path segment is allowed, has: '" +
path[i:] + "' in path '" + fullPath + "'")
default:
end++
}
}
// check if this Node existing children which would be
// unreachable if we insert the wildcard here
if len(n.children) > 0 {
panic("wildcard route '" + path[i:end] +
"' conflicts with existing children in path '" + fullPath + "'")
}
// check if the wildcard has a name
if end-i < 2 {
panic("wildcards must be named with a non-empty name in path '" + fullPath + "'")
}
if c == ':' { // param
// split path at the beginning of the wildcard
if i > 0 {
n.path = path[offset:i]
offset = i
}
child := &node{
nType: param,
maxParams: numParams,
}
n.children = []*node{child}
n.wildChild = true
n = child
n.priority++
numParams--
// if the path doesn't end with the wildcard, then there
// will be another non-wildcard subpath starting with '/'
if end < max {
n.path = path[offset:end]
offset = end
child := &node{
maxParams: numParams,
priority: 1,
}
n.children = []*node{child}
n = child
}
} else { // catchAll
if end != max || numParams > 1 {
panic("catch-all routes are only allowed at the end of the path in path '" + fullPath + "'")
}
if len(n.path) > 0 && n.path[len(n.path)-1] == '/' {
panic("catch-all conflicts with existing handle for the path segment root in path '" + fullPath + "'")
}
// currently fixed width 1 for '/'
i--
if path[i] != '/' {
panic("no / before catch-all in path '" + fullPath + "'")
}
n.path = path[offset:i]
// first node: catchAll node with empty path
child := &node{
wildChild: true,
nType: catchAll,
maxParams: 1,
}
n.children = []*node{child}
n.indices = string(path[i])
n = child
n.priority++
// second node: node holding the variable
child = &node{
path: path[i:],
nType: catchAll,
maxParams: 1,
handlers: handlers,
priority: 1,
}
n.children = []*node{child}
return
}
}
// insert remaining path part and handle to the leaf
n.path = path[offset:]
n.handlers = handlers
}
n.nType = root // node 类型为根 path
}
}
}
return group.returnObj()
{
if group.root {
return group.engine
}
return group
}
}
}
frontApi.POST("/action0", user.Signin)
adminAPI := engine.Group("/api/admin", middleware.RefreshTokenCookie, middleware.AdminRequired)
adminAPI.GET("/ctrl0/action0", user.AllList)
adminAPI.POST("/action1", baidu.PushToBaidu)
}
// 运行
engine.Run(":8080")
{
defer func() { debugPrintError(err){
if err != nil {
debugPrint("[ERROR] %v\n", err)
{
if IsDebugging() {
log.Printf("[GIN-debug] "+format, values...)
}
}
}
} }()
address := resolveAddress(addr)
{
switch len(addr) {
case 0: // 没有配置监听地址
if port := os.Getenv("PORT"); port != "" {
debugPrint("Environment variable PORT=\"%s\"", port)
return ":" + port
}
debugPrint("Environment variable PORT is undefined. Using port :8080 by default")
return ":8080"
case 1: // 有配置监听地址
return addr[0]
default:
panic("too much parameters")
}
}
debugPrint("Listening and serving HTTP on %s\n", address)
// 使用 go 核心的 http 库,engine.ServeHTTP(....) 作为处理器
err = http.ListenAndServe(address, engine)
{
// address === ":8080"
// handler === engine.ServeHTTP(....)
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
{
// addr === ":8080"
addr := srv.Addr
if addr == "" {
addr = ":http"
}
ln, err := net.Listen("tcp", addr)
{
// func Listen(network, address string) (Listener, error)
addrs, err := DefaultResolver.resolveAddrList(context.Background(), "listen", network, address, nil)
if err != nil {
return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: nil, Err: err}
}
var l Listener
switch la := addrs.first(isIPv4).(type) {
case *TCPAddr:
l, err = ListenTCP(network, la) // Tcp 类型的监听
case *UnixAddr:
l, err = ListenUnix(network, la) // Unix 类型的监听
default:
return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: address}}
}
if err != nil {
return nil, err // l is non-nil interface containing nil pointer
}
return l, nil
}
if err != nil {
return err
}
return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}) // func (srv *Server) Serve(l net.Listener)
{
//type tcpKeepAliveListener struct {
// *net.TCPListener
//}
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(){
srv.nextProtoOnce.Do(srv.onceSetNextProtoDefaults_Serve)
return srv.nextProtoErr
}; err != nil {
return err
}
srv.trackListener(l, true)
{
s.mu.Lock()
defer s.mu.Unlock()
if s.listeners == nil {
s.listeners = make(map[net.Listener]struct{})
}
if add {
// If the *Server is being reused after a previous
// Close or Shutdown, reset its doneChan:
if len(s.listeners) == 0 && len(s.activeConn) == 0 {
s.doneChan = nil
}
s.listeners[ln] = struct{}{}
} else {
delete(s.listeners, ln)
}
}
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()
{
return func (ln tcpKeepAliveListener) Accept() (net.Conn, error) {
tc, err := ln.AcceptTCP()
if err != nil {
return nil, err
}
tc.SetKeepAlive(true)
tc.SetKeepAlivePeriod(3 * time.Minute)
return tc, nil
}
}
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 := &conn{ // !!!!!!创建连接 !!!!!!
server: srv, // ------------------------------------ 对Server的引用
rwc: rwc, // 客户端连接
}
if debugServerConnections {
c.rwc = newLoggingConn("server", c.rwc)
}
return c
}
c.setState(c.rwc, StateNew) // before Serve can return
{
srv := c.server
switch state {
case StateNew:
srv.trackConn(c, true)
case StateHijacked, StateClosed:
srv.trackConn(c, false)
}
c.curState.Store(connStateInterface[state])
if hook := srv.ConnState; hook != nil {
hook(nc, state)
}
}
go c.serve(ctx) // ------------------------------------------- 创建例程,在此支持高并发
{
// func (c *conn) serve(ctx context.Context)
c.remoteAddr = c.rwc.RemoteAddr().String() // 客户端地址
ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr())
defer func() {
if err := recover(); err != nil && err != ErrAbortHandler {
const size = 64 << 10
buf := make([]byte, size)
buf = buf[:runtime.Stack(buf, false)]
c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)
}
if !c.hijacked() {
c.close()
c.setState(c.rwc, StateClosed)
}
}()
if tlsConn, ok := c.rwc.(*tls.Conn); ok { // c === &conn{ server: srv === Server, rwc: rwc === 客户端连接 , }
if d := c.server.ReadTimeout; d != 0 { // c.server === Server
c.rwc.SetReadDeadline(time.Now().Add(d))
}
if d := c.server.WriteTimeout; d != 0 {
c.rwc.SetWriteDeadline(time.Now().Add(d))
}
if err := tlsConn.Handshake(); err != nil {
c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)
return
}
c.tlsState = new(tls.ConnectionState)
*c.tlsState = tlsConn.ConnectionState()
if proto := c.tlsState.NegotiatedProtocol; validNPN(proto) {
if fn := c.server.TLSNextProto[proto]; fn != nil {
h := initNPNRequest{tlsConn, serverHandler{c.server}}
fn(c.server, tlsConn, h)
}
return
}
}
// HTTP/1.x from here on.
ctx, cancelCtx := context.WithCancel(ctx)
c.cancelCtx = cancelCtx
defer cancelCtx()
// !!!!!! c === &conn{ server: srv === Server , rwc: rwc === 客户端连接 , }
c.r = &connReader{conn: c} // !!!!!! Reader
c.bufr = newBufioReader(c.r) // !!!!!! Reader
c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10) // !!!!!! Writer
for {
w, err := c.readRequest(ctx)
{
if c.hijacked() {
return nil, ErrHijacked
}
var (
wholeReqDeadline time.Time // or zero if none
hdrDeadline time.Time // or zero if none
)
t0 := time.Now()
if d := c.server.readHeaderTimeout(); d != 0 {
hdrDeadline = t0.Add(d)
}
if d := c.server.ReadTimeout; d != 0 {
wholeReqDeadline = t0.Add(d)
}
c.rwc.SetReadDeadline(hdrDeadline)
if d := c.server.WriteTimeout; d != 0 {
defer func() {
c.rwc.SetWriteDeadline(time.Now().Add(d))
}()
}
c.r.setReadLimit(c.server.initialReadLimitSize())
if c.lastMethod == "POST" {
// RFC 2616 section 4.1 tolerance for old buggy clients.
peek, _ := c.bufr.Peek(4) // ReadRequest will get err below
c.bufr.Discard(numLeadingCRorLF(peek))
}
// 创建 Request 对象
req, err := readRequest(c.bufr, keepHostHeader)
{
tp := newTextprotoReader(b)
req = new(Request) // ---------------------------- 创建 Request 对象
// First line: GET /index.html HTTP/1.0
var s string
if s, err = tp.ReadLine(); err != nil {
return nil, err
}
defer func() {
putTextprotoReader(tp)
if err == io.EOF {
err = io.ErrUnexpectedEOF
}
}()
var ok bool
req.Method, req.RequestURI, req.Proto, ok = parseRequestLine(s)
if !ok {
return nil, &badStringError{"malformed HTTP request", s}
}
if !validMethod(req.Method) { // 是否是支持的方法
return nil, &badStringError{"invalid method", req.Method}
}
rawurl := req.RequestURI // 请求地址
if req.ProtoMajor, req.ProtoMinor, ok = ParseHTTPVersion(req.Proto); !ok {
return nil, &badStringError{"malformed HTTP version", req.Proto}
}
// CONNECT requests are used two different ways, and neither uses a full URL:
// The standard use is to tunnel HTTPS through an HTTP proxy.
// It looks like "CONNECT www.google.com:443 HTTP/1.1", and the parameter is
// just the authority section of a URL. This information should go in req.URL.Host.
//
// The net/rpc package also uses CONNECT, but there the parameter is a path
// that starts with a slash. It can be parsed with the regular URL parser,
// and the path will end up in req.URL.Path, where it needs to be in order for
// RPC to work.
justAuthority := req.Method == "CONNECT" && !strings.HasPrefix(rawurl, "/")
if justAuthority {
rawurl = "http://" + rawurl
}
if req.URL, err = url.ParseRequestURI(rawurl); err != nil { // 解析成功 req.URL 对象
return nil, err
}
if justAuthority {
// Strip the bogus "http://" back off.
req.URL.Scheme = ""
}
// Subsequent lines: Key: value.
// 读取 MIME 头
mimeHeader, err := tp.ReadMIMEHeader()
if err != nil {
return nil, err
}
// 请求头
req.Header = Header(mimeHeader)
// 请求主机
// RFC 2616: Must treat
// GET /index.html HTTP/1.1
// Host: www.google.com
// and
// GET http://www.google.com/index.html HTTP/1.1
// Host: doesntmatter
// the same. In the second case, any Host line is ignored.
req.Host = req.URL.Host
if req.Host == "" {
req.Host = req.Header.get("Host") // 获取 Host 信息
}
if deleteHostHeader {
delete(req.Header, "Host")
}
fixPragmaCacheControl(req.Header)
req.Close = shouldClose(req.ProtoMajor, req.ProtoMinor, req.Header, false)
err = readTransfer(req, b)
if err != nil {
return nil, err
}
if req.isH2Upgrade() {
// Because it's neither chunked, nor declared:
req.ContentLength = -1
// We want to give handlers a chance to hijack the
// connection, but we need to prevent the Server from
// dealing with the connection further if it's not
// hijacked. Set Close to ensure that:
req.Close = true
}
return req, nil
}
if err != nil {
if c.r.hitReadLimit() {
return nil, errTooLarge
}
return nil, err
}
if !http1ServerSupportsRequest(req) {
return nil, badRequestError("unsupported protocol version")
}
c.lastMethod = req.Method // 请求方法
c.r.setInfiniteReadLimit()
hosts, haveHost := req.Header["Host"] // 请求头的 Host
isH2Upgrade := req.isH2Upgrade()
if req.ProtoAtLeast(1, 1) && (!haveHost || len(hosts) == 0) && !isH2Upgrade && req.Method != "CONNECT" {
return nil, badRequestError("missing required Host header")
}
if len(hosts) > 1 {
return nil, badRequestError("too many Host headers")
}
if len(hosts) == 1 && !httplex.ValidHostHeader(hosts[0]) {
return nil, badRequestError("malformed Host header")
}
for k, vv := range req.Header {
if !httplex.ValidHeaderFieldName(k) {
return nil, badRequestError("invalid header name")
}
for _, v := range vv {
if !httplex.ValidHeaderFieldValue(v) {
return nil, badRequestError("invalid header value")
}
}
}
delete(req.Header, "Host") // 删除请求头的 Host
ctx, cancelCtx := context.WithCancel(ctx)
req.ctx = ctx
req.RemoteAddr = c.remoteAddr // 远程
req.TLS = c.tlsState
if body, ok := req.Body.(*body); ok {
body.doEarlyClose = true
}
// Adjust the read deadline if necessary.
if !hdrDeadline.Equal(wholeReqDeadline) {
c.rwc.SetReadDeadline(wholeReqDeadline)
}
w = &response{ // ---------------------------- 创建 response 对象
// !!!!!! c === &conn{ server: srv === Server , rwc: rwc === 客户端连接 , }
conn: c,
cancelCtx: cancelCtx,
req: req, // Request 对象
reqBody: req.Body, // Request的Body对象
handlerHeader: make(Header),
contentLength: -1,
closeNotifyCh: make(chan bool, 1),
// We populate these ahead of time so we're not
// reading from req.Header after their Handler starts
// and maybe mutates it (Issue 14940)
wants10KeepAlive: req.wantsHttp10KeepAlive(),
wantsClose: req.wantsClose(),
}
if isH2Upgrade {
w.closeAfterReply = true
}
w.cw.res = w // 对response的引用
w.w = newBufioWriterSize(&w.cw, bufferBeforeChunkingSize)
return w, nil
}
if c.r.remain != c.server.initialReadLimitSize() {
// If we read any bytes off the wire, we're active.
c.setState(c.rwc, StateActive)
}
if err != nil {
const errorHeaders = "\r\nContent-Type: text/plain; charset=utf-8\r\nConnection: close\r\n\r\n"
if err == errTooLarge {
// Their HTTP client may or may not be
// able to read this if we're
// responding to them and hanging up
// while they're still writing their
// request. Undefined behavior.
const publicErr = "431 Request Header Fields Too Large"
fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)
c.closeWriteAndWait()
return
}
if isCommonNetReadError(err) {
return // don't reply
}
publicErr := "400 Bad Request"
if v, ok := err.(badRequestError); ok {
publicErr = publicErr + ": " + string(v)
}
fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)
return
}
// Expect 100 Continue support
req := w.req // Request 对象
if req.expectsContinue() {
if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {
// Wrap the Body reader with one that replies on the connection
req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
}
} else if req.Header.get("Expect") != "" {
w.sendExpectationFailed()
return
}
c.curReq.Store(w)
if requestBodyRemains(req.Body) {
registerOnHitEOF(req.Body, w.conn.r.startBackgroundRead)
} else {
if w.conn.bufr.Buffered() > 0 {
w.conn.r.closeNotifyFromPipelinedRequest()
}
w.conn.r.startBackgroundRead()
}
// HTTP cannot have multiple simultaneous active requests.[*]
// Until the server replies to this request, it can't read another,
// so we might as well run the handler in this goroutine.
// [*] Not strictly true: HTTP pipelining. We could let them all process
// in parallel even if their responses need to be serialized.
// But we're not going to implement HTTP pipelining because it
// was never deployed in the wild and the answer is HTTP/2.
//type serverHandler struct {
// srv *Server
//}
// !!!创建 serverHandler 对象,并调用 ServeHTTP(w, w.req) 方法 !!!
// w === response 对象
// w.req === Request 对象
serverHandler{c.server}.ServeHTTP(w, w.req)
{
//func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
// handler === engine
handler := sh.srv.Handler
if handler == nil {
handler = DefaultServeMux
}
if req.RequestURI == "*" && req.Method == "OPTIONS" {
handler = globalOptionsHandler{}
}
// handler === engine
handler.ServeHTTP(rw, req)
{
//func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// !!! --------------- 创建上下文 --------------
c := engine.pool.Get().(*Context) // === engine.allocateContext()
{
//type Context struct {
// writermem responseWriter
// Request *http.Request // Request 对象
// Writer ResponseWriter
//
// Params Params
// handlers HandlersChain
// index int8
//
// engine *Engine
//
// // Keys is a key/value pair exclusively for the context of each request.
// Keys map[string]interface{}
//
// // Errors is a list of errors attached to all the handlers/middlewares who used this context.
// Errors errorMsgs
//
// // Accepted defines a list of manually accepted formats for content negotiation.
// Accepted []string
//}
return &Context{engine: engine}
}
c.writermem.reset(w)
{
// c.writermem.reset === responseWriter.reset
//func (w *responseWriter) reset(writer http.ResponseWriter) {
w.ResponseWriter = writer // !!!!!! response 对象
w.size = noWritten
w.status = defaultStatus
//}
}
c.Request = req // !!!!!! Request 对象
c.reset()
{
c.Writer = &c.writermem // responseWriter 对象
c.Params = c.Params[0:0]
c.handlers = nil
c.index = -1
c.Keys = nil
c.Errors = c.Errors[0:0]
c.Accepted = nil
}
engine.handleHTTPRequest(c)
{
// c ==== Context 上下文
//func (engine *Engine) handleHTTPRequest(c *Context) {
httpMethod := c.Request.Method
path := c.Request.URL.Path // 如: "/dir0/dir1"
unescape := false
if engine.UseRawPath && len(c.Request.URL.RawPath) > 0 { // 使用 RawPath 路径
path = c.Request.URL.RawPath
unescape = engine.UnescapePathValues
}
// Find root of the tree for the given HTTP method
t := engine.trees
for i, tl := 0, len(t); i < tl; i++ {
if t[i].method == httpMethod { // 判断请求方式,如:"POST"
root := t[i].root
// Find route in tree !!! ---------------------------------------------- 查找路由
handlers, params, tsr := root.getValue(path, c.Params, unescape)
{
// func (n *node) getValue(path string, po Params, unescape bool) (handlers HandlersChain, p Params, tsr bool) {
p = po
walk: // Outer loop for walking the tree
for {
if len(path) > len(n.path) { // "请求地址的长度"大于"路由地址长度"
if path[:len(n.path)] == n.path { // 前缀匹配
path = path[len(n.path):]
// If this node does not have a wildcard (param or catchAll)
// child, we can just look up the next child node and continue
// to walk down the tree
if !n.wildChild {
c := path[0]
for i := 0; i < len(n.indices); i++ {
if c == n.indices[i] {
n = n.children[i]
continue walk
}
}
// Nothing found.
// We can recommend to redirect to the same URL without a
// trailing slash if a leaf exists for that path.
tsr = path == "/" && n.handlers != nil
return
}
// handle wildcard child
n = n.children[0]
switch n.nType {
case param:
// find param end (either '/' or path end)
end := 0
for end < len(path) && path[end] != '/' {
end++
}
// save param value
if cap(p) < int(n.maxParams) {
p = make(Params, 0, n.maxParams)
}
i := len(p)
p = p[:i+1] // expand slice within preallocated capacity
p[i].Key = n.path[1:]
val := path[:end]
if unescape {
var err error
if p[i].Value, err = url.QueryUnescape(val); err != nil {
p[i].Value = val // fallback, in case of error
}
} else {
p[i].Value = val
}
// we need to go deeper!
if end < len(path) {
if len(n.children) > 0 {
path = path[end:]
n = n.children[0]
continue walk
}
// ... but we can't
tsr = len(path) == end+1
return
}
if handlers = n.handlers; handlers != nil {
return
}
if len(n.children) == 1 {
// No handle found. Check if a handle for this path + a
// trailing slash exists for TSR recommendation
n = n.children[0]
tsr = n.path == "/" && n.handlers != nil
}
return
case catchAll:
// save param value
if cap(p) < int(n.maxParams) {
p = make(Params, 0, n.maxParams)
}
i := len(p)
p = p[:i+1] // expand slice within preallocated capacity
p[i].Key = n.path[2:]
if unescape {
var err error
if p[i].Value, err = url.QueryUnescape(path); err != nil {
p[i].Value = path // fallback, in case of error
}
} else {
p[i].Value = path
}
handlers = n.handlers
return
default:
panic("invalid node type")
}
}
} else if path == n.path { // !!!!地址完全匹配 !!!!
// We should have reached the node containing the handle.
// Check if this node has a handle registered.
if handlers = n.handlers; handlers != nil {
return
}
if path == "/" && n.wildChild && n.nType != root {
tsr = true
return
}
// No handle found. Check if a handle for this path + a
// trailing slash exists for trailing slash recommendation
for i := 0; i < len(n.indices); i++ {
if n.indices[i] == '/' {
n = n.children[i]
tsr = (len(n.path) == 1 && n.handlers != nil) ||
(n.nType == catchAll && n.children[0].handlers != nil)
return
}
}
return
}
// Nothing found. We can recommend to redirect to the same URL with an
// extra trailing slash if a leaf exists for that path
tsr = (path == "/") ||
(len(n.path) == len(path)+1 && n.path[len(path)] == '/' &&
path == n.path[:len(n.path)-1] && n.handlers != nil)
return
}
// }
}
if handlers != nil {
c.handlers = handlers // 处理器
c.Params = params
c.Next() // !!!! -------------- 执行处理器链条
{
//func (c *Context) Next() {
c.index++
for s := int8(len(c.handlers)); c.index < s; c.index++ {
c.handlers[c.index](c) // !!!! --------------- 执行处理器
}
//}
}
// 写 http 响应头
c.writermem.WriteHeaderNow()
{
// w === responseWriter
if !w.Written() {
w.size = 0
// w.ResponseWriter === response 对象
w.ResponseWriter.WriteHeader(w.status)
}
}
return
}
if httpMethod != "CONNECT" && path != "/" {
if tsr && engine.RedirectTrailingSlash {
redirectTrailingSlash(c)
return
}
if engine.RedirectFixedPath && redirectFixedPath(c, root, engine.RedirectFixedPath) {
return
}
}
break
}
}
if engine.HandleMethodNotAllowed { // 被禁止的方法
for _, tree := range engine.trees {
if tree.method != httpMethod { // 查找"请求方法不匹配,但是路由匹配"的handler
if handlers, _, _ := tree.root.getValue(path, nil, unescape); handlers != nil {
c.handlers = engine.allNoMethod
// default405Body = []byte("405 method not allowed")
serveError(c, 405, default405Body)
return
}
}
}
}
c.handlers = engine.allNoRoute // 找不到路由
// default404Body = []byte("404 page not found")
serveError(c, 404, default404Body)
{
//var mimePlain = []string{MIMEPlain}
//func serveError(c *Context, code int, defaultMessage []byte) {
c.writermem.status = code
c.Next() // !!!! -------------- 执行处理器链条
if !c.writermem.Written() {
if c.writermem.Status() == code {
c.writermem.Header()["Content-Type"] = mimePlain
c.Writer.Write(defaultMessage)
} else {
c.writermem.WriteHeaderNow()
}
}
// }
}
//}
}
// 放入上下文
engine.pool.Put(c)
//}
}
//}
}
w.cancelCtx()
if c.hijacked() {
return
}
w.finishRequest()
if !w.shouldReuseConnection() {
if w.requestBodyLimitHit || w.closedRequestBodyEarly() {
c.closeWriteAndWait()
}
return
}
c.setState(c.rwc, StateIdle)
c.curReq.Store((*response)(nil))
if !w.conn.server.doKeepAlives() {
// We're in shutdown mode. We might've replied
// to the user without "Connection: close" and
// they might think they can send another
// request, but such is life with HTTP/1.1.
return
}
if d := c.server.idleTimeout(); d != 0 {
c.rwc.SetReadDeadline(time.Now().Add(d))
if _, err := c.bufr.Peek(4); err != nil {
return
}
}
c.rwc.SetReadDeadline(time.Time{})
}
}
}
}
}
}
return
}