go-httpserver

默认路由注册器分析

image

使用http.handlerFunc

	http.HandleFunc("/handleFunc", func(writer http.ResponseWriter, request *http.Request) {
		writer.Write([]byte("我是HandleFun函数类型"))
	})
	http.ListenAndServe(":8080", nil)
  • 注册了一个/handlerFun接口
  • 启动服务

路由注册源码分析

既然能直接将一个接口对应一个方法,底部实现应该是有一个变量进行存储,如map[string]muxEntry。最后在http协议分析的时候,匹配请求地址,找到了就执行对应的handler方法。

疑问1?http.HandleFunc()仅仅是一个函数,里面注册的路由如何能与http.ListenAndServe()这个独立方法关联在一起呢?

答:既然是两个独立的函数,他们内部的变量肯定不能共享,所以要想注册的路由在启动分析中使用,则一定是设置了一个全局变量。所以追踪代码找到了DefaultServeMux默认的路由服务

源码http.server.go line:2451


func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    // 调用ServerMux中的HandleFunc来注册回调方法,这里仅仅是对匿名函数的一层封装,后面我们可以试着来手动封住,实现一样的功能
	DefaultServeMux.HandleFunc(pattern, handler)
}

// line:2436
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	if handler == nil {
		panic("http: nil handler")
	}
	// 这里调用了ServeMux中的handle方法,路由=>处理Handler接口变量!因为匹配到了路由,那么我们要执行什么代码呢?肯定是要定义一个接口,然后外部统一实现这个接口,在框架底层就直接调用这个接口中的方法就行。这个就是接口的好处了。
	mux.Handle(pattern, HandlerFunc(handler))
}

使用http.handle

func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }

上面这里还是使用的DefaultServeMux,这里是直接传的参数是实现了handler的接口,相比于http.handleFunc这个更加是底层一步的方法。这里需要手动实现handler接口,而http.handleFunc是只要传入一个匿名函数,它会帮实现handler接口。区别仅此而已

自己实现handleFunc

因为想传入匿名函数,所以定义一个函数类型就行了,然后这个函数类型实现handler接口就ok了嘛。其实实现完成之后发现这个在go 中已经封装了。就是http.HandlerFunc这个类型

package main

import (
	"fmt"
	"net/http"
)

// 定义一个类型是函数类型,因为我也像http.handleFunc一样传入匿名函数
type HandleMyFunc func(writer http.ResponseWriter, request *http.Request)

// 这里是实现了handler接口
func (f HandleMyFunc) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	fmt.Println("ServeHttp")
	f(writer, request)
}

func main() {

	var hh HandleMyFunc
	hh = func(writer http.ResponseWriter, request *http.Request) {
		writer.Write([]byte("模拟handFunc1"))
	}
	http.Handle("/handleMyFunc1", hh)
	
	http.Handle("/handleMyFunc2", HandleMyFunc(func(writer http.ResponseWriter, request *http.Request) {
		writer.Write([]byte("模拟handFunc2"))
	}))

	http.ListenAndServe(":8080", nil)
}

路由匹配规则

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
}
  • m 是一个map,会在匹配的时候优先精确匹配
  • es 是路由注册的时候以/为结尾,会保存在这个切片中(长度从大到小),后面匹配的时候,如果精确匹配没有结果,则会以这个里面的路由进行就近匹配
posted @ 2020-06-08 19:35  Sentiger  阅读(427)  评论(0编辑  收藏  举报