• 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 是路由注册的时候以/为结尾,会保存在这个切片中(长度从大到小),后面匹配的时候,如果精确匹配没有结果,则会以这个里面的路由进行就近匹配
  • 相关阅读:
    C# 编译机器码过程原理之再谈反射
    百度Echarts中国地图经纬度
    网页客服思路以及QQ截图粘贴到聊天框功能
    Linux查看CPU和内存使用情况
    Java 打包方式
    电商系统 常用代码 MyBatis-Plus
    Java cnpm install 没有反应
    Java 项目无法运行 解决
    电商系统 常用代码 VUE
    电商系统 常用代码段 Element-ui
  • 原文地址:https://www.cnblogs.com/shiwenhu/p/13067850.html
Copyright © 2020-2023  润新知