GoWeb之实现简单的WebServer(一)

今天,我们来学习如何建立一个简单的WebServer。

一、分析WebServer

既然要进行实现,那必须参考其他Web框架是如何搭建Server的,这里我们用Gin来举例

打开源码,gin的Server命名为Engine,忽略其他字段,会发现最重要的是一个叫做RouterGroup的结构体,这个结构体的作用是:构建路由树。

参考整个实现,会发现除了Router之外,还有Context上下文,用于封装对于http的发送和请求的一些操作,但Context并不在Engine里面,所以这里暂时不讨论

那么,Engine有什么作用呢,参考下面示例代码:

func TestEngine(t *testing.T){
    r := gin.Default()
	r.Group("/", func(c *gin.Context) {})
	r.Run(":8080")
}

由上可知,Engine的主要作用就是两个:

  1. 构造对应的路由树,并存放相应的业务逻辑
  2. 启动并监听对应的端口

因此,有了上面的这些内容,我们就可以自己来实现一个简单的WebServer

二、实现WebServer

话不多说,直接上代码

首先,Context是用来串联我们整个http链路的关键。例如在gin中Context可以用来进行字段的绑定等等操作,它是请求来的信息和我们要进行操作的业务逻辑中间的桥梁。

1. 简单的Context

这个Context,我们还没想好它要做什么,参考Gin的Context,所以暂时只用来对请求和响应进行一些封装

type Context struct {
	Req  *http.Request
	Resp http.ResponseWriter
}

2. 简单的路由树结构体

围绕着这个路由树我们该怎么进行补充和完善的内容,篇幅过长,我们分几期来讲

type route struct{}

3. 组合并实现

因为Server的操作都是大同小异,所以,我们选择定义一个接口,让用户只专注于Server方法的调用,并且可以保证,如果我们需要其他不同操作的Server,可以实现这个接口,保证代码的扩展性

package serv

import (
	"net/http"
)

// 保证Serv这个结构体一定实现了Server接口
var _ Server = &Serv{}

// HandlerFunc 就是我们的业务逻辑
type HandleFunc func(ctx Context)

// Server Server的api应该设计成什么样子
type Server interface {
    //
	ServeHTTP(writer http.ResponseWriter, request *http.Request)

    // 启动并监听
	Run(addr string) error

    // 这是第一版,暂时在Server上来添加,实际我们需要在route中定义方法进行添加
	AddRoute(method string, path string, handler HandleFunc)
}

type Serv struct {
	*router
}

func NewServ() Server {
	// 这里暂时还没写好Router,所以我先不初始化
	return &Serv{}
}

// ServeHTTP 
// 这里这么实现,是因为打开http的源码,发现http里的handler接口就是这么定义的
func (s *Serv) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
	ctx := Context{
		Req:  request,
		Resp: writer,
	}

	//查找路由树,并执行路由代码
	s.Serve(ctx)

}

func (s *Serv) Serve(ctx Context) {}

func (s *Serv) AddRoute(method string, path string, handler HandleFunc) {
	//panic("implement me")
}

// Get 我们的核心始终是AddRoute,所以接口里不实现Get方法,而是交给衍生的结构体去实现
func (s *Serv) Get(path string, handler HandleFunc) {
	s.AddRoute(http.MethodGet, path, handler)
}

func (s *Serv) Run(addr string) error {
	err := http.ListenAndServe(addr, s)
	return err
}

4. 注意事项

  • 对于 Serv 的 Get 方法,其实是参考了 Gin的 Handle , 其实所有 method 的本质就是调用了在图中,一个叫做 group.handler  的方法,而我们的Server,则是叫做AddRoute
  • Run方法中,如果我们需要加入一个监听机制,可以不直接使用 http.ListenAndServe  方法,而是使用 net.Listen ,然后插入你的监听机制(例如 prometheus 等等),最后再使用 http.Serve 方法
  • func Run(){
        listen, err := net.Listen("tcp", addr)
    	if err != nil {
    		// 打印日志 或者 panic
    	}
    	// 插入你的监听逻辑
    	
    	http.Serve(listen, nil)
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值