本书未发布

5.11. Eudore特性演示

未匹配的标注

特性演示

本部分主要展示Eudore主要特性,一些框架基本功能就不介绍了。

自定义Handler

eudore创新之一,赋予无限的Context扩展。

在其他框架处理函数都是一个固定的函数,而eudore几乎支持任意处理函数,只需要额外注册一下转换函数,将任意函数转换成eudore.HanderFunc对象即可,在基于路由匹配返回字符串的benckmark测试中,处理函数转换造成的性能丢失低于1%。

基于处理函数扩展机制,可以给处理请求的请求上下文添加任意函数。

可以使用eudore.DefaultHandlerExtend.ListExtendHandlerFun()函数查看内置支持的任意函数类型,如果是注册了不支持的处理函数类型会触发panic。

内置部分扩展处理函数类型:

func(func(eudore.ContextData)) eudore.HandlerFunc
func(eudore.handlerHTTP) eudore.HandlerFunc
func(http.Handler) eudore.HandlerFunc
func(func(http.ResponseWriter, *http.Request)) eudore.HandlerFunc
func(http.HandlerFunc) eudore.HandlerFunc
func(func()) eudore.HandlerFunc
func(func() interface {}) eudore.HandlerFunc
func(func() error) eudore.HandlerFunc
func(func(eudore.Context) error) eudore.HandlerFunc
func(func(eudore.Context) interface {}) eudore.HandlerFunc
func(func(eudore.Context) (interface {}, error)) eudore.HandlerFunc
func(func(eudore.Context, map[string]interface {}) (interface {}, error)) eudore.HandlerFunc
func(interface {}) eudore.HandlerFunc
func(func() string) eudore.HandlerFunc
func(fmt.Stringer) eudore.HandlerFunc

例如使用多种处理函数:

func main() {
    app := eudore.NewApp()
    app.AnyFunc("/*", func(ctx eudore.Context) {
        ctx.WriteString("hello eudore")
    })
    // 如果返回error不为空,会返回500和请求id。
    app.GetFunc("/check", func(ctx eudore.Context) error {
        if len(ctx.GetQuery("value")) > 3 {
            return fmt.Errorf("value is %s len great 3", ctx.GetQuery("value"))
        }
        return nil
    })
    // 对返回的数据调用Render格式化。
    app.GetFunc("/data", func(ctx eudore.Context) interface{} {
        return map[string]string{
            "a": "1",
            "b": "2",
        }
    })
    app.Listen(":8080")
    app.Run()
}

实现一个扩展函数

MyContext额外实现了一个Hello方法,然后使用eudore.RegisterHandlerFunc注册一个转换函数,转换函数要求参数是一个函数,返回参数是一个eudore.HandlerFunc。

闭包一个func(fn func(MyContext)) eudore.HandlerFunc转换函数,就将MyContext类型处理函数转换成了eudore.HandlerFunc,然后就可以使用路由注册自己定义的处理函数。

例子

package main

import (
    "github.com/eudore/eudore"
    "github.com/eudore/eudore/component/httptest"
)

// MyContext 定义新的请求上下文扩展。
type MyContext struct {
    eudore.Context
}

func main() {
    app := eudore.NewApp()
    app.AddHandlerExtend(func(fn func(MyContext)) eudore.HandlerFunc {
        return func(ctx eudore.Context) {
            fn(MyContext{ctx})
        }
    })
    app.GetFunc("/*", func(ctx MyContext) {
        ctx.Hello()
    })

    client := httptest.NewClient(app)
    client.NewRequest("GET", "/hello").Do().Out()
    for client.Next() {
        app.Error(client.Error())
    }
    client.Stop(0)

    app.Run()
}

// Hello 方法返回hello。
func (ctx MyContext) Hello() {
    ctx.WriteString("hello")
}

强大的路由

eudore创新之二,低逻辑复杂度实现强大的路由器。

零内存复制,高性能,Erouter匹配性能静态路由具有httprouter的70%,api匹配性能具有90%且内存分配仅消耗httprouter六分之一,但是具有严格路由匹配顺序、易扩展重写和代码复杂度低的特点。

eudore路由器分离出的erouter和httprouter性能测试结果:

goos: linux
goarch: amd64
pkg: github.com/eudore/web-framework-benchmark
BenchmarkHttprouterStatic-2            50000         25686 ns/op        1949 B/op        157 allocs/op
BenchmarkHttprouterGitHubAPI-2         30000         52997 ns/op       16571 B/op        370 allocs/op
BenchmarkHttprouterGplusAPI-2         500000          2570 ns/op         813 B/op         24 allocs/op
BenchmarkHttprouterParseAPI-2         500000          3791 ns/op         986 B/op         42 allocs/op
BenchmarkErouterRadixStatic-2          50000         34314 ns/op        1950 B/op        157 allocs/op
BenchmarkErouterRadixGitHubAPI-2       30000         57850 ns/op        2786 B/op        203 allocs/op
BenchmarkErouterRadixGplusAPI-2       500000          2468 ns/op         173 B/op         13 allocs/op
BenchmarkErouterRadixParseAPI-2       300000          4551 ns/op         323 B/op         26 allocs/op
BenchmarkErouterFullStatic-2           50000         34728 ns/op        1950 B/op        157 allocs/op
BenchmarkErouterFullGitHubAPI-2        30000         62151 ns/op        2787 B/op        203 allocs/op
BenchmarkErouterFullGplusAPI-2        500000          2570 ns/op         173 B/op         13 allocs/op
BenchmarkErouterFullParseAPI-2        300000          4362 ns/op         323 B/op         26 allocs/op
PASS
ok      github.com/eudore/web-framework-benchmark   22.356s

具有匹配优先级,优先级为常量>变量>通配符。

app.AnyFunc("/*", func(ctx eudore.Context) {
    ctx.WriteString("hello eudore core")
})
app.GetFunc("/get/:name", func(ctx eudore.Context) {
    ctx.WriteString("get name: " + ctx.GetParam("name") + "\n")
})
app.GetFunc("/get/eudore", func(ctx eudore.Context) {
    ctx.WriteString("get eudore\n")
})

Any方法不会覆盖其他方法,注册Any方法路由会注册全部方法。

app.GetFunc("/*path", func(ctx eudore.Context) {
    ctx.WriteString("get path: /" + ctx.GetParam("path") + "\n")
})
// Any方法不会覆盖Get方法。
app.AnyFunc("/*path", func(ctx eudore.Context) {
    ctx.WriteString("any path: /" + ctx.GetParam("path") + "\n")
})

支持路由器重新扩展,扩展对变量和通配符具有多种校验功能,通配符的校验和变量使用方法一样,都具有匹配优先级。

app := eudore.NewApp()

// 修改路由
app.Router = eudore.NewRouterFull()
eudore.Set(app.Router, "print", eudore.NewPrintFunc(app))

// 正则校验,相当于 regexp:^0.*$,是一个动态校验函数。
app.GetFunc("/get/:num|^0.*$", func(ctx eudore.Context) {
    ctx.WriteString("first char is '0', num is: " + ctx.GetParam("num") + "\n")
})
// 动态校验函数,min闭包生成校验函数。
app.GetFunc("/get/:num|min:100", func(ctx eudore.Context) {
    ctx.WriteString("num great 100, num is: " + ctx.GetParam("num") + "\n")
})
// 校验函数,使用校验函数isnum。
app.GetFunc("/get/:num|isnum", func(ctx eudore.Context) {
    ctx.WriteString("isnum num is: " + ctx.GetParam("num") + "\n")
})

默认参数,路由路径使用空格分割,第一个字符串是路由路径,其他字符串是键值对的参数,当前用于模板、鉴权、熔断器。

app.AnyFunc("/* version=v0", func(ctx eudore.Context) {
    fmt.Println("version:", ctx.GetParam("version"))
})

mvc支持

eudore控制器实现通过分析控制器得到路由方法路径和闭包执行控制器方法。

控制器接口需要实现初始化、释放和注入三个方法,初始化和释放完成控制器对象的初始化和释放过程,用于支持Before和After逻辑,Inject方法完成注入控制器路由到路由器中。

type Controller interface {
    Init(Context) error
    Release(Context) error
    Inject(Controller, RouterMethod) error
}

eudore控制器实现Controller接口即可,默认内置ControllerBase、ControllerData、ControllerSingleton、ControllerView四种控制器。

  • ControllerBase 为最基本的控制器,嵌入Context对象。
  • ControllerData 在ControllerBase基础上使用嵌入ContextData对象。
  • ControllerSingleton 作为一个单例控制器。
  • ControllerView 在ControllerData基础上添加了默认模板参数,如果未写入响应数据,会使用Data属性来渲染响应数据。

例如创建一个简单的控制器:

type MyBaseController struct {
    eudore.ControllerBase
}

func (ctl *MyBaseController) Any() {
    ctl.Info("MyBaseController Any")
}
func (*MyBaseController) Get() interface{} {
    return "get MyBaseController"
}
func (ctl *MyBaseController) GetInfoById() interface{} {
    return ctl.GetParam("id")
}

func main() {
    app := eudore.NewApp()
    app.AddController(new(MyBaseController))

    app.Listen(":8080")
    app.Run()
}

控制器方法参数和请求上下文处理相同,也可以使用扩展类型。

http server解耦

eudore通过Server接口使用框架和http Server解耦,屏蔽各类Server实现的细节。

type Server interface {
    SetHandler(http.Handler)
    Serve(net.Listener) error
    Shutdown(ctx context.Context) error
}

eudore拥有nethttp、eudore两种server,适配后fasthttp server需要分配大量内存且不常用,已删除相关,如果对server源码了解程度不高,建议使用app默认nethttp。

  • nethttp server使用nethttp库启动服务,作为默认的server。
  • eudore server是重新实现http/1.1的server,不保证可靠性
// 使用eudore server
import (
    "github.com/eudore/eudore"
    eserver "github.com/eudore/eudore/component/server/eudore"
)

func main() {
    app := eudore.NewApp(eserver.NewServer())
    app.AnyFunc("/*", func(ctx eudore.Context) {
        ctx.WriteString("start fasthttp server, this default page.\n")
        ctx.WriteString("your path is " + ctx.Path())
    })
    app.Listen(":8088")
    app.Run()
}

反馈和交流请加群组:QQ群373278915

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~