gobox中的http请求处理框架

135 阅读3分钟
原文链接: mp.weixin.qq.com

女主宣言

今天和大家介绍下我们自主开发的go语言轻型框架gobox,为什么叫gobox呢?因为我们设计让每一个单独的模块都作为一个box,那这些box的集合就称为gobox,再使用go的pkg管理机制引入到项目中。随着go官方推出了dep这个包管理工具,我们把gobox中的每一个box都单独拿出来作为一个项目管理,这就是现在的gobox;今天这一期,主要来说下使用gobox中的http请求处理框架。

PS:丰富的一线技术、多元化的表现形式,尽在“360云计算”,点关注哦!

http请求处理架构图

重要的对象

System

system用于实现go官方包中的http.Handler接口,它的ServeHTTP方法中实现了请求处理框架。

Router

定义和实现MVC的路由查找过程。

    type Router interface {

    MapRouteItems(cls ...controller.Controller) // 自动将Controller对象中的Action方法映射到路由表

    DefineRouteItem(pattern string, cl controller.Controller, actionName string) // 手动添加路由规则,pattern为正则表达式

    FindRoute(path string) *Route // 实现路由查找过程

    }

SimpleRouter

Router接口的一个实现,自动映射规则为:

  1. controller名称规则为: ([ A- Z][ A- Za- z0- 9_ ]*)Controller$,匹配内容转小写即为controllerName

  2. action名称规则为: ^([ A- Z][ A- Za- z0- 9_ ]*)Action$,匹配内容转小写后过滤掉  before 和after即为actionName

自动路由查找规则如下:

  1. 将request_uri视为: /controller/ action

  2. controller不存在,则默认为 index,可以修改

  3. action不存在,则默认为 index,可以修改

自定义路由查找规则如下:

  1. 对request_uri做正则匹配

  2. 如果匹配后存在捕获,则捕获内容会作为action中除context外的参数,依次传入,都是string类型

ActionContext和Controller

ActionContext

处理每个请求会创建一个对应Controller的ActionContext对象:

    type ActionContext interface {

    Request() *http.Request

    ResponseWriter() http.ResponseWriter

    ResponseBody() []byte

    SetResponseBody(body []byte)

    BeforeAction()

    AfterAction()

    Destruct()

    }

Controller

组织Action:

    type Controller interface {

    NewActionContext(req *http.Request, respWriter http.ResponseWriter) ActionContext

    }

gracehttp

这是一个支持平滑重启的httpserver,平滑重启过程如下:

示例代码

最后附上一个最简单的使用示例:

    package main

    import (

    "github.com/goinbox/gohttp/controller"

    "github.com/goinbox/gohttp/gracehttp"

    "github.com/goinbox/gohttp/router"

    "github.com/goinbox/gohttp/system"

    "net/http"

    )

    func main() {

    dcl := new(DemoController)

    r := router.NewSimpleRouter()

    r.DefineRouteItem("^/g/([0-9]+)$", dcl, "get")

    r.MapRouteItems(new(IndexController), dcl)

    sys := system.NewSystem(r)

    gracehttp.ListenAndServe(":8001", sys)

    }

    type BaseActionContext struct {

    Req *http.Request

    RespWriter http.ResponseWriter

    RespBody []byte

    }

    func (this *BaseActionContext) Request() *http.Request {

    return this.Req

    }

    func (this *BaseActionContext) ResponseWriter() http.ResponseWriter {

    return this.RespWriter

    }

    func (this *BaseActionContext) ResponseBody() []byte {

    return this.RespBody

    }

    func (this *BaseActionContext) SetResponseBody(body []byte) {

    this.RespBody = body

    }

    func (this *BaseActionContext) BeforeAction() {

    this.RespBody = append(this.RespBody, []byte(" index before ")...)

    }

    func (this *BaseActionContext) AfterAction() {

    this.RespBody = append(this.RespBody, []byte(" index after ")...)

    }

    func (this *BaseActionContext) Destruct() {

    println(" index destruct ")

    }

    type IndexController struct {

    }

    func (this *IndexController) NewActionContext(req *http.Request, respWriter http.ResponseWriter) controller.ActionContext {

    return &BaseActionContext{

    Req: req,

    RespWriter: respWriter,

    }

    }

    func (this *IndexController) IndexAction(context *BaseActionContext) {

    context.RespBody = append(context.RespBody, []byte(" index action ")...)

    }

    func (this *IndexController) RedirectAction(context *BaseActionContext) {

    system.Redirect302("https://github.com/goinbox")

    }

    type DemoActionContext struct {

    *BaseActionContext

    }

    func (this *DemoActionContext) BeforeAction() {

    this.RespBody = append(this.RespBody, []byte(" demo before ")...)

    }

    func (this *DemoActionContext) AfterAction() {

    this.RespBody = append(this.RespBody, []byte(" demo after ")...)

    }

    func (this *DemoActionContext) Destruct() {

    println(" demo destruct ")

    }

    type DemoController struct {

    }

    func (this *DemoController) NewActionContext(req *http.Request, respWriter http.ResponseWriter) controller.ActionContext {

    return &DemoActionContext{

    &BaseActionContext{

    Req: req,

    RespWriter: respWriter,

    },

    }

    }

    func (this *DemoController) DemoAction(context *DemoActionContext) {

    context.RespBody = append(context.RespBody, []byte(" demo action ")...)

    }

    func (this *DemoController) GetAction(context *DemoActionContext, id string) {

    context.RespBody = append(context.RespBody, []byte(" get action id = "+id)...)

    }

运行这个代码,请求示例及输出如下:

    curl http://127.0.0.1:8001/

    index before index action index after

    curl http://127.0.0.1:8001/index/redirect -I

    HTTP/1.1 302 Found

    Content-Type: text/html; charset=utf-8

    Location: https://github.com/goinbox

    Date: Fri, 24 Aug 2018 11:57:11 GMT

    Content-Length: 14

    curl http://127.0.0.1:8001/demo/demo

    demo before demo action demo after

    curl http://127.0.0.1:8001/g/123

    demo before get action id = 123 demo after

所有destruct输出为:

    index destruct

    index destruct

    index destruct

    demo destruct

    demo destruc

欢迎大家使用,使用中有遇到问题随时反馈,我们会尽快响应,谢谢!

360云计算

由360云平台团队打造的技术分享公众号,内容涉及数据库、大数据、微服务、容器、AIOps、IoT等众多技术领域,通过夯实的技术积累和丰富的一线实战经验,为你带来最有料的技术分享