GO七天开发挑战:7天实现Web框架-Gee(day 2)

学习资料来自:GitHub - geektutu/7days-golang: 7 days golang programs from scratch (web framework Gee, distributed cache GeeCache, object relational mapping ORM framework GeeORM, rpc framework GeeRPC etc) 7天用Go动手写/从零实现系列

Day2 独立路由 & 设计上下文结构封装数据

构建独立路由

文件路径 :Web-Gee/gee/router.go

  • 结构体 router,存放路由地址以及处理程序。

func newRouter() *router {
	return &router{handlers: make(map[string]HandlerFunc)}
}
  • 将路由地址与对应的处理程序添加到路由哈希表中。
func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {
	log.Printf("Route %4s - %s", method, pattern)
	key := method + "-" + pattern
	r.handlers[key] = handler
}
  •  根据路由地址调用对应的处理程序,若地址不存在则返回 404 NOT FOUND。
func (r *router) handle(c *Context) {
	key := c.Method + "-" + c.Path
	if handler, ok := r.handlers[key]; ok {
		handler(c)
	} else {
		c.String(http.StatusNotFound, "404 NOT FOUND: %s\\n", c.Path)
	}
}

设计上下文结构封装数据(包括请求和响应数据)

文件路径 :Web-Gee/gee/context.go

  • 结构体 Context,封装所需的各类型数据。
type Context struct {
	// 待封装的数据对象
	Writer http.ResponseWriter
	Req    *http.Request
	// 请求的详细信息
	Path   string
	Method string
	// 响应的详细信息
	StatusCode int
}

func newContext(w http.ResponseWriter, req *http.Request) *Context {
	return &Context{
		Writer: w,
		Req:    req,
		Path:   req.URL.Path,
		Method: req.Method,
	}
}
  • 各个基本方法

    (1)返回 r.Form(解析好的表单数据,包括URL字段的query参数和POST或PUT的表单数据) 中以key为键的[]string字符串切片的第一个值。

func (c *Context) PostForm(key string) string {
	return c.Req.FormValue(key)
}

    (2)URL.Query() :解析 RawQuery 字段,返回对应的 Values 类型键值对。再根据键值 key 返回对应的值。 

func (c *Context) Query(key string) string {
	return c.Req.URL.Query().Get(key)
}

    (3)显示调用 WriteHeader ,发送 http 回复的头域和状态码。 

func (c *Context) Status(code int) {
	c.StatusCode = code
	c.Writer.WriteHeader(code)
}

    (4)Header()方法: 返回一个Header类型值,该值会被WriteHeader方法发送(注意:在调用WriteHeader或Write方法后再改变该对象是没有意义的)。

             Set(key, value string)方法:向Header对象添加键值对,如键已存在则会用只有新值一个元素的切片取代旧值切片。

func (c *Context) SetHeader(key string, value string) {
	c.Writer.Header().Set(key, value)
}

    (5) Write()方法:向连接中写入一部分http的回复数据。如果Header中没有"Content-Type"键,本方法会使用包函数DetectContentType检查数据的前512字节,将返回值作为该键的值(调用 SetHeader 方法)。如果被调用时还未调用WriteHeader,本方法会先调用WriteHeader(http.StatusOK)(调用 Status 方法)

func (c *Context) String(code int, format string, values ...interface{}) {
	c.SetHeader("Content-Type", "text/plain")
	c.Status(code)
	c.Writer.Write([]byte(fmt.Sprintf(format, values)))
}
  • 支持JSON,HTML等返回类型

    (1)JSON类型

func (c *Context) JSON(code int, obj interface{}) {
	c.SetHeader("Content-Type", "application/json")
	c.Status(code)
	encoder := json.NewEncoder(c.Writer)
	if err := encoder.Encode(obj); err != nil {
		http.Error(c.Writer, err.Error(), 500)
	}
}

    (2)HTML类型

func (c *Context) HTML(code int, html string) {
	c.SetHeader("Content-Type", "text/html")
	c.Status(code)
	c.Writer.Write([]byte(html))
}

(3)其它类型数据

func (c *Context) Data(code int, data []byte) {
	c.Status(code)
	c.Writer.Write(data)
}


main 函数测试路由

文件位置:Web-Gee/main.go

  • GET 请求,“/” 路由,返回 HTML 数据
r.GET("/", func(c *gee.Context) {
	c.HTML(http.StatusOK, "

Hello Gee

") })
  •  POST 请求,“/login” 路由,返回 JSON 数据
r.POST("/login", func(c *gee.Context) {
	c.JSON(http.StatusOK, gee.H{
		"username": c.PostForm("username"),
		"password": c.PostForm("password"),
	})
})
  • GET 请求,“/hello” 路由,返回其它类型数据
r.GET("/hello", func(c *gee.Context) {
	c.String(http.StatusOK, "hello %s, you're at %s\n", c.Query("name"), c.Path)
})


 运行测试

在终端使用 curl命令 进行路由测试

  • “/” 路由 :返回对应的 HTML 数据

GO七天开发挑战:7天实现Web框架-Gee(day 2)_第1张图片

  • “/hello”路由 :返回相应的数据 

  • “/login”路由 :反对对应的 JSON 数据

  •  “/xxx” 路由:未保存的路由,输出 404 not found

DAY2 :完成上下文结构的设计  

你可能感兴趣的:(Go,leetcode)