echo源码分析
Posted golang算法架构leetcode技术php
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了echo源码分析相关的知识,希望对你有一定的参考价值。
web框架的核心作用有三个:分层、路由、中间件。针对于go比较有名的web框架有
https://github.com/labstack/echo
https://github.com/gin-gonic/gin
https://github.com/kataras/iris
https://beego.me/docs/intro/
https://github.com/go-martini/martini
其中echo 是一个比较轻量级的框架,下面基于echo@v1.4.4对它的源码进行分析。
主要有下面6个文件和三个目录组成。
binder.go
context.go
echo.go
group.go
response.go
router.go
middleware
_fixture
website
其中middleware里面定义了最基本最常用的四个中间件
auth.go
compress.go
logger.go
recover.go
_fixture是一些网页资源
% ls _fixture
favicon.ico folder images index.html
website 是说明文档,中间有个Dockerfile 可以在本地编译镜像,跑起来
% ls website
Dockerfile config.json layouts
argo.json content static
首先我们看下如何使用echo
package main
import (
"net/http"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
// 创建一个echo实例
e := echo.New()
// 注册中间件
// 需要我们在入口文件手动注入基础中间件
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// 注册路由
e.GET("/", hello)
// 启动服务
e.Logger.Fatal(e.Start(":1323"))
}
// 路由handle提出来了而已
// 匿名函数方式 不重要
func hello(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
}
1,echo.go文件
New函数定义在echo.go 文件里面
func New() (e *Echo) {
e = &Echo{
// 创建一个http Server指针
Server: new(http.Server),
// 创建一个https的 Server指针
TLSServer: new(http.Server),
AutoTLSManager: autocert.Manager{
Prompt: autocert.AcceptTOS,
},
// 日志实例
Logger: log.New("echo"),
// 控制台、日志可以彩色输出的实例
colorer: color.New(),
maxParam: new(int),
}
// http server绑定实现了server.Handler的实例
// 也就是说Echo框架自身实现了http.Handler接口
e.Server.Handler = e
// https server绑定实现了server.Handler的实例
e.TLSServer.Handler = e
// 绑定http服务异常处理的handler
e.HTTPErrorHandler = e.DefaultHTTPErrorHandler
//
e.Binder = &DefaultBinder{}
// 设置日志输出级别
e.Logger.SetLevel(log.ERROR)
// 绑定标准日志输出实例
e.StdLogger = stdLog.New(e.Logger.Output(), e.Logger.Prefix()+": ", 0)
// 绑定获取请求上下文实例的闭包
e.pool.New = func() interface{} {
return e.NewContext(nil, nil)
}
// 绑定路由实例
e.router = NewRouter(e)
// 绑定路由map
// 注意这个属性的含义:路由分组用的,key为host,则按host分组
// 记住与Router.routes区别
// Router.routes存的路由的信息(不包含路由的handler)
e.routers = map[string]*Router{}
return
}
手先初始化了一个echo对象,然后定义了一个DefaultBinder,实现了Binder接口,这个接口定义在bind.go文件里,后面介绍
Binder interface {
Bind(i interface{}, c Context) error
}
接着设置了日志级别为ERROR,设置了标准输出Logger,然后初始化了一个Context 对象
// NewContext returns a Context instance.
func (e *Echo) NewContext(r *http.Request, w http.ResponseWriter) Context {
return &context{
request: r,
response: NewResponse(w, e),
store: make(Map),
echo: e,
pvalues: make([]string, *e.maxParam),
handler: NotFoundHandler,
}
}
context 对象和interface 都定义在context.go文件中,后面讲解context .go文件的时候详细讲解.
其中的Map定义如下
Map map[string]interface{}
context里面存储了
r *http.Request, w http.ResponseWriter
这也就是为什么写echo的controller的时候只用传 context对象就行,而标准的http包需要顶替包含参数r *http.Request, w http.ResponseWriter的HandleFunc
最后初始化了路由(router.go)里面实现的
func NewRouter(e *Echo) *Router {
// 初始化Router
return &Router{
// 路由树
// 路由的信息(包含路由的handler)
// 查找路由用的LCP (最长公共前缀)算法
tree: &node{
// 节点对应的不同http method的handler
methodHandler: new(methodHandler),
},
// Router.routes存的路由的信息(不包含路由的handler)
routes: map[string]*Route{},
// 框架实例自身
echo: e,
}
Router的定义如下
Router struct {
tree *node
routes map[string]*Route
echo *Echo
}
是一个棵多叉树,其中tree存储了当前节点里面的值,它的定义如下
node struct {
kind kind
label byte
prefix string
parent *node
children children
ppath string
pnames []string
methodHandler *methodHandler
}
接着我们看下如何定义路由的,已get请求为例
e.GET("/stats", func(c echo.Context) error {
return c.JSON(200, s.Data())
})
它的定义如下
func (e *Echo) GET(path string, h HandlerFunc, m ...MiddlewareFunc) *Route {
return e.Add(http.MethodGet, path, h, m...)
}
我们可以看到,它的内部调用了Add方法,其实POST、PATCH、DELETE等http method类似都是对Add方法进行了包裹
Add方法的参数有http请求的方法,请求路径,对应的处理函数和中间件参数。
func (e *Echo) Add(method, path string, handler HandlerFunc, middleware ...MiddlewareFunc) *Route {
// 获取handler的名称
//
以上是关于echo源码分析的主要内容,如果未能解决你的问题,请参考以下文章
Android 事件分发事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )(代码片段
mysql jdbc源码分析片段 和 Tomcat's JDBC Pool
Android 逆向ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 )(代码片段
Android 逆向ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 )(代码片段