手写goweb框架前三部分 【按网上教程操作】

119 阅读3分钟

为什么需要gin框架而不用传统的内置的net/http包?

因为net/http包提供了基础的web功能,即监听端口、静态路由、解析http报文,但是一些web开发中的基础功能并不支持,需要手工实现。例如:

  • 动态路由: hello/:name , hello/* 这类规则
  • 鉴权:没有分组/统一鉴权的能力,需要在每个路由映射的handler中实现。
  • 模板:没有统一简化的HTML机制。
  • ....

传统net/http实现

func HelloServer(w http.ResponseWriter,req *http.Request) {
	fmt.Println("Inside HelloServer handler")
//	req.FormValue("val")  //获取post请求中的表单 val对应的值
	fmt.Fprintf(w,"hello,"+req.URL.Path[1:])  // req.URL.Path[1:] 表示丢弃路径中的/ 截取路径中/后的字符串
	// io.WriteString(w,"hello,"+req.URL.Path[1:])
	title := "简单服务器"
	fmt.Fprintf(w, "<h1>%s</h1><div>%s</div>", title, req.URL.Path[1:])
}

func main() {
	//路径前缀匹配 匹配路径以/开头的请求
	http.HandleFunc("/",HelloServer)
    err := http.ListenAndServe("localhost:8080",nil)
	if err != nil {
		log.Fatal("ListenAndServer",err.Error())
	}
}

上面的代码中我们定义了一个路由以及对应路由的handler,main函数中监听8080端口,用来启动web服务,当我们访问该路由就会转到对应的处理器。ListenAndServe方法中两个参数第一个是监听的端口,第二是处理所有http请求的实例,当为空的时候就会使用标准库的实例处理,就是上面对应的每个路由对应的handler。

type Handler interface { ServeHTTP(ResponseWriter, *Request) }

点开发现第二个参数是一个接口,有一个servehttp方法,只要实现了该接口的实例都可以传入上面的函数,这时所有的http请求都会转入该实例由该实例进行实现。这是实现web框架的入口。

type Engine struct{}

func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
   switch req.URL.Path {
   case "/":
      fmt.Fprintf(w, "URL,PATH=%q\n", req.URL.Path)
   case "/heelo":
      for k, v := range req.Header {
         fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
      }
   default:
      fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)
   }
}

func main() {
   engine := new(Engine)
   http.ListenAndServe(":8080", engine)
}

上述是简单的自定义处理实例的一个实现,会发现监听8080端口后,所有请求都转入engine中的servehttp中处理。 对比用net\http包中的处理来说,自定义处理逻辑拦截了所有的http请求,在其中可以定义路由的映射逻辑和实现一些事务处理,而标准库只能实现一些静态路由。

自定义http请求处理实现静态路由

type HandlerFunc func(w http.ResponseWriter, req *http.Request)

type Engine struct {
   router map[string]HandlerFunc  //存储路由映射到具体的handler
}

func New() *Engine {
   return &Engine{
      router: make(map[string]HandlerFunc),
   }
}

func (engine *Engine) addRoute(method, pattern string, handlerFunc HandlerFunc) {
   key := method + "-" + pattern
   engine.router[key] = handlerFunc
}              

func (engine *Engine) GET(pattern string, handlerFunc HandlerFunc) {  //注册GET路由
   engine.addRoute("GET", pattern, handlerFunc)           
}

func (engine *Engine) POST(pattern string, handlerFunc HandlerFunc) { //注册GET路由
   engine.addRoute("POST", pattern, handlerFunc)
}

func (engine *Engine) Run(addr string) {         //对listenandserve的包装 启动服务器监听
   err := http.ListenAndServe(addr, engine)   
   if err != nil {
      log.Fatal("监听端口失败", err)
   }
}

//实现servehttP方法 一切请求转入该方法执行 
func (engine *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
   key := r.Method + "-" + r.URL.Path
   if handler, ok := engine.router[key]; ok {
      handler(w, r)         //根据不同的请求转入相应的处理方法 --已经注册的路由,未注册返回404
   } else {
      fmt.Fprintf(w, "404 NOT FOUND %s\n", r.URL)
   }
}

main 中进行调用

r := gee.New()
r.GET("/hello", func(w http.ResponseWriter, req *http.Request) {
   fmt.Fprintf(w, "hello world")
})
r.Run(":8080")

资料来源:geektutu.com/post/gee.ht…