Skip to content
/ eudore Public
forked from eudore/eudore

I am using the go web server framework to learn the http protocol.

Notifications You must be signed in to change notification settings

zhbok/eudore

This branch is 37 commits behind eudore/eudore:master.

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Apr 14, 2019
62cc027 · Apr 14, 2019

History

9 Commits
Apr 14, 2019
Apr 14, 2019
Apr 14, 2019
Apr 7, 2019
Apr 14, 2019
Apr 7, 2019
Apr 14, 2019
Mar 31, 2019
Mar 31, 2019
Mar 31, 2019
Mar 17, 2019
Mar 24, 2019
Apr 7, 2019
Mar 31, 2019
Apr 7, 2019
Apr 14, 2019
Apr 14, 2019
Apr 14, 2019
Apr 14, 2019
Feb 6, 2019
Mar 31, 2019
Apr 14, 2019
Apr 14, 2019
Apr 14, 2019
Apr 14, 2019
Apr 14, 2019
Apr 14, 2019
Apr 7, 2019
Mar 24, 2019
Apr 14, 2019
Apr 14, 2019
Mar 24, 2019
Mar 24, 2019
Mar 24, 2019
Apr 14, 2019
Apr 14, 2019
Apr 14, 2019
Apr 14, 2019
Apr 14, 2019
Mar 24, 2019
Feb 6, 2019
Feb 6, 2019
Mar 31, 2019
Mar 24, 2019

Repository files navigation

Eudore

本框架为个人学习研究的重框架,每周最多同步更新一次,未稳定前不欢迎issue、pr、using,可查看http及go web框架相关文档,交流q群373278915。

Features

  • 核心全部接口化,支持重写Application、Context、Request、Response、Router、Middleware、Logger、Server、Config、Cache、Bind、Render、View。
  • 对象语义明确,框架源码简单易懂注释多,无注释部分变动可能较大。

Lsit

功能列表,在未稳定前不会编写演示

  • Application
  • 程序启动流程自定义实现,内置两种
  • server异步启动
  • 完全配置化启动程序
  • Context
  • Context与server完全解耦
  • 根据Content-type自动序列化数据
  • 根据Accept反序列化数据
  • 内部重定向支持
  • http2 push
  • Config
  • 配置库集成
  • 支持基于路径读写对象
  • map和结构体相互转换
  • 数据类型转换工具
  • 生成对象帮助信息
  • Server
  • 支持net/http启动server
  • 支持fasthttp启动server
  • 重新实现http协议server
  • http2协议两种server支持
  • fastcgi协议两种server支持
  • websocket协议支持
  • 重新实现websocket协议
  • 支持TLS和双向TLS
  • 自动自签TLS证书
  • quic协议支持
  • http3协议学不动了
  • server热重启支持
  • server后台启动
  • Router
  • 零内存复制快速路由器实现
  • 严格路由匹配顺序
  • RESTful风格基于方法的路由注册匹配
  • 基于Host进行路由注册匹配
  • 路由器注册初始化时请求处理
  • 组路由注册支持
  • 全局中间件注册
  • 组级中间件注册
  • api级中间件注册
  • 路由默认参数
  • 默认参数匹配注册中间件
  • 路由匹配参数捕获
  • 路由匹配参数校验
  • 路由匹配参数正则捕捉
  • 路由匹配通配符捕捉
  • 路由匹配通配符校验
  • 路由匹配通配符正则捕捉
  • Logger
  • 初始化期间日志处理
  • 日志条目属性支持
  • 自定义模板格式化
  • 日志写入到es
  • View
  • 多模板库接入
  • Mvc
  • mvc支持
  • before和after执行
  • 控制器函数输出参数
  • Tools
  • 程序启动命令解析
  • 信号响应支持
  • SRI值自动设置
  • 自动http2 push
  • http代理实现
  • pprof支持
  • expvar支持
  • 运行时对象数据显示
  • Middleware
  • gzip压缩
  • 限流
  • 黑名单
  • Session实现

issue

setting 基于配置初始化对象未实现

缺少完整websocket实现,仅有upgrade部分

config-eudore未测试,已实现通过路径设置获得属性。

组件Set方法等待config-eudore实现后复用功能

fasthttp不支持多端口和hijack

handlefile处理304缓存

mvc未完善

Component

组件名称 介绍 定义库
router-radix 使用基数树实现标准功能路由器 内置
router-full 使用基数树实现完整功能路由器 内置
router-init 初始时使用的路由处理 github.com/eudore/eudore/component/router/init
router-host 匹配host路由到不同路由器处理 github.com/eudore/eudore/component/router/host
logger-init 初始化日志处理,保存日志由设置的日志对象处理 内置
logger-std 基础日志库实现 内置
logger-elastic 将日志直接输出到es中 未更新、github.com/eudore/eudore/component/eslogger
server-std 使用net/http封装标准库Server 内置
server-eudore 使用protocol库封装Server github.com/eudore/eudore/component/server/eudore
server-fasthttp 使用fasthttp启动服务 github.com/eudore/eudore/component/server/fasthttp
cache-map 使用Sync.Map实现的缓存 内置
cache-group 使用前缀匹配的多缓存组合 内置
config-map 使用map[string]interface{}存储配置 内置
config-eudore 使用反射来操作结构体和map自由嵌套的配置对象 内置
view-std 使用标准库html/template渲染模板 内置、未测试

Example

Example部分未更新

Application

Application默认有两种实现Core和Eudore,Core只有启动函数,Eudore多一些辅助函数封装。

func main() {
	// 运行core
	core := eudore.NewCore()
	go core.Run()

	// 运行eudore
	e := eudore.NewEudore()
	e.Run()
}

Server

Server是eudore用于启动http服务的顶级接口对象之一。

func main() {
	e := eudore.NewEudore()
	// 直接设置Server对象
	e.Server, _ = eudore.NewServer("server-std", nil)

	// 加载Server组件,设置一个启动端口,设置超时时间
	e.RegisterComponent("server", &eudore.ServerConfigGeneral{
		Addr:	"8088",
		ReadTimeout:	12 * time.Second,
		WriteTimeout:	4 * time.Second,
	})

	// 启动多个端口
	// 端口8085:设置证书、开启https http2、关闭双向htttps
	e.RegisterComponent("server-multi", &eudore.ServerMultiConfig{
		Configs:	[]interface{}{
			&eudore.ServerConfigGeneral{
				Name:	"server",
				Addr:	"8085",
				Https:	true,
				Http2:	true,
				Mutual:	false,
				Certfile:	"/etc/...",
				Keyfile:	"/etc/...",
			},
			&eudore.ServerConfigGeneral{
				Name:	"server",
				Addr:	"8086",
			},
		},
	})
	e.Run()
}

Logger

NewEudore创建App时,会创建logger-init日志组件,实现LoggerInitHandler接口,改组件会将日志条目存储起来,直到加载下一个日志组件时,使用新日志组件处理所有存储的日子条目。

logger-std的Std用于输出标准输出;若Path为空会强制Std为true;Format会使用存储的LoggerFormatFunc函数,若无法匹配会使用text/template模板格式化日志。

func main() {
	e := eudore.NewEudore()
	e.Debug("init 1")
	e.Get("/get", get)
	e.Post("/post", post)
	e.RegisterComponent("logger-std", &eudore.LoggerStdConfig{
		Std:	true,
		Path:	"access.log",
		Level:	"debug",
//		Format:	"json",
		Format:	`[{{.Timestamp.Format "Jan 02, 2006 15:04:05 UTC"}}] {{.Level}}: {{.Message}}`,
	})
	e.Debug("init 2")
	e.Run()
}

Router and Middleware

router-std路由器支持组路由、组级中间件、路径参数、通配符参数、默认参数。

router-full路由器支持组路由、组级中间件、路径参数、通配符参数、默认参数、参数校验、通配符校验,未实现多参数正则捕捉。

可实现Router接口重写路由器。

curl -XGET http://localhost:8088/api/v1/

curl -XGET http://localhost:8088/api/v1/get/eudore

curl -XGET http://localhost:8088/api/v1/set/eudore

package main

import (
	"github.com/eudore/eudore"
	"github.com/eudore/eudore/middleware/logger"
	"github.com/eudore/eudore/middleware/recover"
)

// eudore core
func main() {
	// 创建App
	app := eudore.NewCore()
	app.RegisterComponent("logger-std", &eudore.LoggerStdConfig{
		Std:	true,
		Level:	eudore.LogDebug,
		Format:	"json",
	})
	// 全局级请求处理中间件
	app.AddMiddleware(
		logger.NewLogger(eudore.GetRandomString).Handle,
	)

	// 创建子路由器
	// apiv1 := eudore.NewRouterClone(app.Router)
	apiv1 := app.Group("/api/v1 version:v1")
	// 路由级请求处理中间件
	apiv1.AddMiddleware(recover.RecoverFunc)
	{
		apiv1.GetFunc("/get/:name", handleget)
		// Api级请求处理中间件
		apiv1.AnyFunc("/*", handlepre1, handleparam)
	}
	// 默认路由
	app.AnyFunc("/*path", func(ctx eudore.Context){
		ctx.WriteString(ctx.Method() + " " + ctx.Path())
		ctx.WriteString("\nstar param: " + " " + ctx.GetParam("path"))
	})
	// 启动server
	app.Listen(":8088")
	app.Run()
}

func handleget(ctx eudore.Context) {
	ctx.Debug("Get: " + ctx.GetParam("name"))
	ctx.WriteString("Get: " + ctx.GetParam("name"))
}
func handlepre1(ctx eudore.Context) {
	ctx.WriteString("\nhandlepre1\n")
}
func handleparam(ctx eudore.Context) {
	ctx.WriteString(ctx.GetParam("*"))
}

Jwt and Session

func main() {
	core := eudore.NewCore()
	core.AddHandler(
		jwt.NewJwt(jwt.NewVerifyHS256("1234")),
		eudore.HandlerFunc(session.SessionFunc),
	)
	core.Any("/", any)
	core.Run()
}

func any(ctx *eudore.Context) {
	ctx.Info(ctx.Value(eudore.ValueJwt))
	ctx.Info(ctx.Value(eudore.ValueSession))

	// inti
	sess := cast.NewMap(ctx.Value(eudore.ValueJwt))
	// get
	ctx.Info(sess.GetInt("uid"))
	// set
	sess.Set("name", "ky2")
	// release,未实现检查map是否变化然后自动释放。
	ctx.SetValue(eudore.ValueSession, sess)

	// inti
	jwt := cast.NewMap(ctx.Value(eudore.ValueSession))
	// get
	ctx.Info(jwt.Get("exp"))
}

Ram

资源访问管理

github.com/eudore/eudore/middleware/ram包共有acl、pbac、rbac、shell四种鉴权方式。

ram.RamHttp对象定义:

type RamHttp struct {
    RamHandler
    GetId     GetIdFunc
    GetAction GetActionFunc
    Forbidden ForbiddenFunc
}
type RamHttp
    func NewRamHttp(rams ...RamHandler) *RamHttp
    func (r *RamHttp) Handle(ctx eudore.Context)
    func (r *RamHttp) Set(f1 GetIdFunc, f2 GetActionFunc, f3 ForbiddenFunc) *RamHttp

RamHttp需要Set设置获取id、获取行为、403执行,三个行为参数。

// bug
package main

import (
	"strconv"
	"github.com/eudore/eudore"
	"github.com/eudore/eudore/middleware/ram"
	"github.com/eudore/eudore/middleware/ram/acl"
)

func main() {
	app := eudore.NewCore()	
	eudore.SetComponent(app.Logger, eudore.LoggerHandleFunc(eudore.LoggerHandleJson))
	// add
	ramAcl := acl.NewAcl()
	ramAcl.AddAllowPermission(1, []string{"Show", "Get"})
	app.AddHandler(
		ram.NewRamHttp(
			// 执行acl鉴权
			ramAcl,
			// rbac.NewRbac(),
			// 默认执行拒绝
			ram.DenyHander,
		).Set(getid, nil, nil),
	)

	app.AnyFunc("/:id/:action ss:00", func(ctx eudore.Context) {
		ctx.Info(ctx.GetParam("action"))
		ctx.WriteString("Allow " + ctx.GetParam("action"))
	})
	app.AnyFunc("/", func(ctx eudore.Context) {
		ctx.Info(ctx.Path())
	})
	// start
	app.Listen(":8088")
	app.Run()
}

func getid(ctx eudore.Context) int {
	i, err := strconv.Atoi(ctx.GetParam("id"))
	if err != nil {
		return 0
	}
	return i
}

Websocket

目前没有独立的websocket库,且不与net/http兼容,推荐使用github.com/gobwas/ws库。

eudore.UpgradeHttp获取net.Conn链接并写入建立请求响应,然后wsutil库读写数据。

ctx.Response().Hijack()可以直接获得原始tcp连接,然后读取header判断请求,写入101数据,再操作websocket连接。

package main

import (
	"github.com/eudore/eudore"
	"github.com/gobwas/ws/wsutil"
)

func main() {
	app := eudore.NewCore()
	eudore.SetComponent(app.Logger, eudore.LoggerHandleFunc(eudore.LoggerHandleJson))
	app.RegisterComponent(eudore.ComponentRouterEmptyName, eudore.HandlerFunc(func(ctx eudore.Context){
		conn, _, err := eudore.UpgradeHttp(ctx) 
		if err != nil {
			// handle error
			ctx.Error(err)
		}
		go func() {
			defer conn.Close()

			for {
				msg, op, err := wsutil.ReadClientData(conn)
				if err != nil {
					ctx.Error(err)
					// handle error
				}
				ctx.Info(string(msg))
				err = wsutil.WriteServerMessage(conn, op, msg)
				if err != nil {
					// handle error
				}
			}
		}()
	}))

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

About

I am using the go web server framework to learn the http protocol.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Go 100.0%