参考教程geektutu.com/post/gee.ht…
今天首先是写了base2的代码,其实和base1(Day3的代码)差不多,作者认为base2可以根据路径switch方法好一点,但是我认为base1的解耦性和可读性都更好,因为对于我这种小白如果不是先看过base1,直接看base2会有点一头雾水,又或许是注释没有写好。
我把base2的代码和注释粘贴下来,大家可以自行比对:
package main
import (
"fmt"
"log"
"net/http"
)
// Engine is the uni handler for all requests
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 "/hello":
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)
log.Fatal(http.ListenAndServe(":1103", engine))
}
// test command
// $ curl "http://localhost:1103/"
// URL.Path = "/"
// $ curl "http://localhost:1103/hello"
//Header["User-Agent"] = ["curl/8.9.1"]
//Header["Accept"] = ["*/*"]
今天我认为比较重要的是base3的gee内容,这比较接近项目核心了(小白的一家之言,因为我感觉我是在模仿gin实现GET、POST、RUN等HTTP方法了),因为不是很熟悉go,所以我做了详细的注释,方便大家观看和我以后回顾。
首先是base3/main.go这里的GET、POST(怎么没有)、RUN,感觉和gin的效果好像一样捏嘻嘻,除了这个gee.New(),我记得gin是Gin.Default()还会自动生成Logger和Recovery中间件。代码如下:
package main
import (
"fmt"
"net/http"
"github.com/EGG-Gerome/gee-web/day1-http-base/base3/gee"
)
func indexHandler(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
}
func helloHandler(w http.ResponseWriter, req *http.Request) {
for k, v := range req.Header {
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
}
}
func main() {
r := gee.New()
r.GET("/", indexHandler)
r.GET("/hello", helloHandler)
r.RUN(":1103")
}
接下来是重要的gee,感觉这个就是gin封装的一些HTTP方法(GET、POST、RUN)。
package gee
import (
"fmt"
"net/http"
)
/*
定义请求处理函数类型:
作用:定义一个函数类型 HandlerFunc,他接受两个参数
http.RespondWriter:用于向客户端发送请求
*http.Request: 客户端的HTTP 请求(指针类型)
意义:所有的路由处理函数都必须符合这个签名,确保接口统一
*/
// 用来规定传入的参数(这里的参数是函数)是这个模式的(函数会有这两个传入)
type HandlerFunc func(http.ResponseWriter, *http.Request)
/*
定义路由器核心结构 Engine
router:一个映射表(map),键为 URL 路径(如"/hello"),值为对应的处理函数(HandlerFunc 类型)
作用:Engine 是路由器的核心,负责存储路径与处理函数的映射关系,并在接收到请求时根据路径找到相应的处理函数
*/
type Engine struct {
router map[string]HandlerFunc
}
/*
构造函数 New()
作用:创建并初始化一个 Engine 实例,返回其指针
关键点:
make(map[string]HandlerFunc):初始化 map,避免空指针异常
返回指针 *Engine 确保所有调用者共享同一个路由器实例(单例模式)
*/
func New() *Engine {
return &Engine{
router: make(map[string]HandlerFunc),
}
}
/*
method(HTTP 请求方法)
类型:string (eg "GET","POST","PUT")
作用:指定请求的 HTTP 方法,区分对同一 URL 的不同操作
pattern(URL路径模式)
类型:string(eg "/","/hello","/user:id")
作用:指定请求的 URL 路径或路径模板,支持静态路径和动态参数
*/
func (engine *Engine) addRoute(method string, pattern string, handler HandlerFunc) {
key := method + "-" + pattern
engine.router[key] = handler
}
// GET defines the method to add GET request
func (engine *Engine) GET(pattern string, handler HandlerFunc) {
engine.addRoute("GET", pattern, handler)
}
// POST defines the method to add POST request
func (engine *Engine) POST(pattern string, handler HandlerFunc) {
engine.addRoute("POST", pattern, handler)
}
// RUN defines the method to start a http server
func (engine *Engine) RUN(addr string) (err error) {
return http.ListenAndServe(addr, engine) // 第二个参数必须是一个实现了 http.Handler 接口的对象。
}
// 第二个参数必须是一个实现了 http.Handler 接口的对象。
// http.Handler 接口定义:
//
// type Handler interface {
// ServeHTTP(w ResponseWriter, r *Request)
// }
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
key := req.Method + "-" + req.URL.Path
if handler, ok := engine.router[key]; ok {
handler(w, req)
} else {
fmt.Fprintf(w, "404 NOTFOUND: %s\n", req.URL)
}
}
这个平台应该是昨天上传的,但是昨天晚上回去,忘了🥹