概述

mqant实现了一个比较简单的http网关,可以用来代理前端发起的http api请求

使用http网关

mqant提供了一个创建代理网关的http.Handler

代码组织结构

首先我们重新组织了一下代码目录结构,新增了一个httpgateway目录用来存放http网关模块代码以及一个后端http handler

    工程目录
        |-bin
            |-conf
                |-server.conf
        |-httpgateway
            |-module.go
        |-main.go

初始化网关监听

var Module = func() module.Module {
    this := new(httpgate)
    return this
}

type httpgate struct {
    basemodule.BaseModule
}

func (self *httpgate) GetType() string {
    //很关键,需要与配置文件中的Module配置对应
    return "httpgate"
}
func (self *httpgate) Version() string {
    //可以在监控时了解代码版本
    return "1.0.0"
}
func (self *httpgate) OnInit(app module.App, settings *conf.ModuleSettings) {
    self.BaseModule.OnInit(self, app, settings)
    self.SetListener(self)
}


func (self *httpgate) startHttpServer() *http.Server {
    srv := &http.Server{
        Addr: ":8090",
        Handler:httpgateway.NewHandler(self.App),
    }
    //http.Handle("/", httpgateway.NewHandler(self.App))

    go func() {
        if err := srv.ListenAndServe(); err != nil {
            // cannot panic, because this probably is an intentional close
            log.Info("Httpserver: ListenAndServe() error: %s", err)
        }
    }()
    // returning reference so caller can call Shutdown()
    return srv
}

func (self *httpgate) Run(closeSig chan bool) {
    log.Info("httpgate: starting HTTP server :8090")
    srv := self.startHttpServer()
    <-closeSig
    log.Info("httpgate: stopping HTTP server")
    // now close the server gracefully ("shutdown")
    // timeout could be given instead of nil as a https://golang.org/pkg/context/
    if err := srv.Shutdown(nil); err != nil {
        panic(err) // failure/timeout shutting down the server gracefully
    }
    log.Info("httpgate: done. exiting")
}

func (self *httpgate) OnDestroy() {
    //一定别忘了继承
    self.BaseModule.OnDestroy()
}

创建网关http.Handler

httpgateway.NewHandler(self.App)

网关默认路径规则

网关默认路由规则是从URL.Path的第一个段取出moduleType

/[moduleType]/path

举例

http://127.0.0.1:8090/httpgate/topic

  • moduleType httpgate
  • hander /httpgate/topic

实现后端http协议

网关转发RPC的handler定义为

func (self *httpgate) httpgateway(request *go_api.Request) (*go_api.Response,error) {}

编写handler

func (self *httpgate) httpgateway(request *go_api.Request) (*go_api.Response,error) {
    mux := http.NewServeMux()
    mux.HandleFunc("/httpgate/topic", func(writer http.ResponseWriter, request *http.Request) {
        writer.Write([]byte(`hello world`))
    })

    req, err := http.NewRequest(request.Method, request.Url, strings.NewReader(request.Body))
    if err != nil {
        return nil,err
    }
    for _,v:=range request.Header{
        req.Header.Set(v.Key, strings.Join(v.Values,","))
    }
    rr := httptest.NewRecorder()
    mux.ServeHTTP(rr, req)
    resp := &go_api.Response{
        StatusCode:  int32(rr.Code),
        Body: rr.Body.String(),
        Header: make(map[string]*go_api.Pair),
    }
    for key, vals := range rr.Header() {
        header, ok := resp.Header[key]
        if !ok {
            header = &go_api.Pair{
                Key: key,
            }
            resp.Header[key] = header
        }
        header.Values = vals
    }
    return    resp,nil
}

注册handler(方案一)

self.GetServer().RegisterGO("/httpgate/topic",self.httpgateway)

注册handler(方案二)

方案一比较固化,跟mqant框架绑定,我们希望能够在编写http函数是能利用golang已存在的web库,又能跟mqant网关结合

利用mqrpc.RPCListener监听未实现的handler,然后将请求通过httptest路由web框架中

当RPC未找到已注册的handler时会调用 func NoFoundFunction(fn string)(*mqrpc.FunctionInfo,error)

func (self *httpgate) NoFoundFunction(fn string)(*mqrpc.FunctionInfo,error){
    return &mqrpc.FunctionInfo{
        Function:reflect.ValueOf(self.httpgateway),
        Goroutine:true,
    },nil
}
func (self *httpgate) BeforeHandle(fn string, callInfo *mqrpc.CallInfo) error{
    return nil
}
func (self *httpgate) OnTimeOut(fn string, Expired int64){

}
func (self *httpgate) OnError(fn string, callInfo *mqrpc.CallInfo, err error){}
func (self *httpgate) OnComplete(fn string, callInfo *mqrpc.CallInfo, result *rpcpb.ResultInfo, exec_time int64){}

设置handler监听器

func (self *httpgate) OnInit(app module.App, settings *conf.ModuleSettings) {
    self.BaseModule.OnInit(self, app, settings)
    self.SetListener(self)
}

运行

2020-05-06T16:09:19.98671+08:00 [-] [-] [development] [I] [rpc_server.go:142] Registering node: httpgate@4bfaf93bd31c512a
2020-05-06T16:09:19.988701+08:00 [-] [-] [development] [I] [ws_server_x.go:131] WS Listen ::3653
2020-05-06T16:09:19.989593+08:00 [-] [-] [development] [I] [tcp_server.go:39] TCP Listen ::3563
2020-05-06T16:09:19.995531+08:00 [-] [-] [development] [I] [module.go:62] httpgate: starting HTTP server :8090

访问

http://127.0.0.1:8090/httpgate/topic

结果

hello world

用gin替代默认http框架

如上的httpgateway函数中,网络框架可以用gin,echo,beego等其他web框架替代

Copyright © 梁大帅 2020 all right reserved,powered by Gitbook该文件修订时间: 2020-05-27 19:24:18

results matching ""

    No results matching ""