代码仓库:
github
gitee
本篇代码请选择分支demo1

中文注释,非常详尽可以配合食用
本篇设计说明草图:

  1. func main() {
  2. http.HandleFunc("/", handler)
  3. http.HandleFunc("/count", counter)
  4. log.Fatal(http.ListenAndServe("localhost:9090", nil))
  5. }
  6. func handler(w http.ResponseWriter, r *http.Request) {
  7. fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
  8. }

标准库中实现了监听,映射路由,和解析http报文。

浏览器的请求,http.ListenAndServe方法中,第一个参数是监听地址响,第二个参数代表处理所有的HTTP请求的实例,nil代表使用标准库中的实例处理。

我们通过第二个参数,转入到我们的实例,这样所有的HTTP请求就都交给了我们的实例来处理。

  1. /*
  2. @Time : 2021/8/5 下午4:08
  3. @Author : mrxuexi
  4. @File : main
  5. @Software: GoLand
  6. */
  7. package main
  8. import (
  9. "fmt"
  10. "log"
  11. "net/http"
  12. )
  13. type Engine struct {}
  14. /**
  15. * @Description:
  16. 对Engine结构体的ServeHttp方法实现。ServeHTTP是Handler接口中的一个方法,在这里我们对这个方法进行实现,放入到我们的Engine中。这里就用上了我们的自定义方法来处理请求。
  17. * @receiver engine
  18. * @param w http.ResponseWriter(通过该ResponseWriter构造针对该请求的响应)
  19. * @param req *http.Request(Request中包括了发送来的HTTP请求的全部信息)
  20. */
  21. func (engine *Engine)ServeHTTP(w http.ResponseWriter, req *http.Request) {
  22. switch req.URL.Path {
  23. case "/":
  24. fmt.Fprintf(w,"URL.Path = %q\n", req.URL.Path)
  25. case "/hello":
  26. for k, v := range req.Header {
  27. fmt.Fprintf(w,"Header[%q] = %q \n", k, v)
  28. }
  29. default:
  30. fmt.Fprintf(w,"404 NOT FOUND: %s\n", req.URL)
  31. }
  32. }
  33. func main() {
  34. engine := new(Engine)
  35. //此处后者的参数填入engine,让请求交由我们实现的engine实例来处理
  36. log.Fatal(http.ListenAndServe(":9090",engine))
  37. }

设计自己的Engine结构体,然后将原来启动web项目的

  1. log.Fatal(http.ListenAndServe(":9090",engine))

封装成Run(addr),并将第二个参数的默认实例,直接写为我们的engine实例。

  1. func (engine *Engine) Run(addr string) (err error) {
  2. return http.ListenAndServe(addr, engine)
  3. }

这里engine涉及到一个转换,实现了接口方法的struct转换为接口类型

我们要实现的GET,POST方法。作用是,将路由和方法,注册进来,然后在监听的时候进行查找和处理。

这里设计一个router放入到我们的Engine结构体中:

  1. // Engine 实现了"net/http"标准库中的 Handler 接口中的ServeHTTP方法
  2. type Engine struct {
  3. //用于存储路由处理方法
  4. //key是方法类型加路径,value是用户的处理方法
  5. router map[string]HandlerFunc
  6. }

我们的GET和POST方法就是这样实现的,调用addRoute方法,将路由和响应方法存入到router中:

  1. // GET 实现的是Engine的处理GET请求的方法,注册到router中
  2. func (engine *Engine) GET(path string, handler HandlerFunc) {
  3. engine.addRoute("GET", path, handler)
  4. }
  5. // POST 同上
  6. func (engine *Engine) POST(path string, handler HandlerFunc) {
  7. engine.addRoute("POST", path, handler)
  8. }

这里就是addRoute方法,method-path作为key,handler作为value

  1. // Engine 中 addRoute 方法,在 router map[string]HandlerFunc 中存入对应处理方法
  2. //存入形式为例如:{ "GET-/index" : 定义的处理方法 }engine
  3. func (engine *Engine) addRoute(method string, path string, handler HandlerFunc) {
  4. key := method + "-" + path
  5. engine.router[key] = handler
  6. }

我们再重写Handler接口中的ServeHTTP方法,通过req请求的路由查找router中注册的方法执行。

  1. // ServeHTTP 方法的实现,用于实现处理HTTP请求
  2. // 先解析req对应传入的路径,查找router中,如果有相应的处理方法,则执行处理方法,如果没有则返回找不到的提示
  3. // 来自Handler接口
  4. func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  5. key := req.Method + "-" + req.URL.Path
  6. //根据请求req中的数据,从router中取出对应的方法
  7. if handler, ok := engine.router[key]; ok {
  8. handler(w, req)
  9. } else {
  10. fmt.Fprintf(w, "could not find the route: %s\n", req.URL)
  11. }
  12. }

雏形的全部源码:

  1. /*
  2. @Time : 2021/8/16 下午4:03
  3. @Author : Mrxuexi
  4. @File : Ez
  5. @Software: GoLand
  6. */
  7. package Ez
  8. import (
  9. "fmt"
  10. "net/http"
  11. )
  12. // HandlerFunc 是Ez框架中定义的对请求的响应处理方法,默认传入这两个参数,针对http请求处理
  13. type HandlerFunc func(http.ResponseWriter, *http.Request)
  14. // Engine 实现了"net/http"标准库中的 Handler 接口中的ServeHTTP方法
  15. type Engine struct {
  16. //用于存储路由处理方法
  17. //key是方法类型加路径,value是用户的处理方法
  18. router map[string]HandlerFunc
  19. }
  20. // ServeHTTP 方法的实现,用于实现处理HTTP请求
  21. // 先解析req对应传入的路径,查找router中,如果有相应的处理方法,则执行处理方法,如果没有则返回找不到的提示
  22. // 来自Handler接口
  23. func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
  24. key := req.Method + "-" + req.URL.Path
  25. //根据请求req中的数据,从router中取出对应的方法
  26. if handler, ok := engine.router[key]; ok {
  27. handler(w, req)
  28. } else {
  29. fmt.Fprintf(w, "could not find the route: %s\n", req.URL)
  30. }
  31. }
  32. // New 是Ez.Engine的构造函数
  33. func New() *Engine {
  34. return &Engine{router: make(map[string]HandlerFunc)}
  35. }
  36. // Engine 中 addRoute 方法,在 router map[string]HandlerFunc 中存入对应处理方法
  37. //存入形式为例如:{ "GET-/index" : 定义的处理方法 }engine
  38. func (engine *Engine) addRoute(method string, path string, handler HandlerFunc) {
  39. key := method + "-" + path
  40. engine.router[key] = handler
  41. }
  42. // GET 实现的是Engine的处理GET请求的方法,注册到router中
  43. func (engine *Engine) GET(path string, handler HandlerFunc) {
  44. engine.addRoute("GET", path, handler)
  45. }
  46. // POST 同上
  47. func (engine *Engine) POST(path string, handler HandlerFunc) {
  48. engine.addRoute("POST", path, handler)
  49. }
  50. // Run 用于启动服务,直接制定用该路由的engine
  51. func (engine *Engine) Run(addr string) (err error) {
  52. return http.ListenAndServe(addr, engine)
  53. }

尝试使用:

  1. /*
  2. @Time : 2021/8/16 下午4:01
  3. @Author : mrxuexi
  4. @File : main
  5. @Software: GoLand
  6. */
  7. package main
  8. import (
  9. "Ez"
  10. "fmt"
  11. "net/http"
  12. )
  13. func main() {
  14. r := Ez.New()
  15. r.GET("/hello", func(w http.ResponseWriter, req *http.Request) {
  16. fmt.Fprintf(w,"Hello")
  17. })
  18. r.Run(":9090")
  19. }

成功!
后续我们继续完善内容

参考:

[1]: https://github.com/geektutu/7days-golang/tree/master/gee-web “”gee””
[2]: https://github.com/gin-gonic/gin “”gin””

版权声明:本文为Mrxuexi原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/Mrxuexi/p/15149490.html