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.gocontext.goecho.gogroup.goresponse.gorouter.gomiddleware_fixturewebsite


其中middleware里面定义了最基本最常用的四个中间件

auth.gocompress.gologger.gorecover.go

_fixture是一些网页资源

 % ls _fixturefavicon.ico folder images index.html

website 是说明文档,中间有个Dockerfile 可以在本地编译镜像,跑起来

 % ls websiteDockerfile config.json layoutsargo.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 )(代码片段

echo源码分析

《Docker 源码分析》全球首发啦!

mysql jdbc源码分析片段 和 Tomcat's JDBC Pool

Android 逆向ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 )(代码片段

Android 逆向ART 脱壳 ( DexClassLoader 脱壳 | DexClassLoader 构造函数 | 参考 Dalvik 的 DexClassLoader 类加载流程 )(代码片段