Gee-Day2-上下文

发布时间 2023-07-18 00:51:43作者: 幕城云空

设计Context

context,顾名思义,就是存储我们在进行路由的时候所需要的各种信息,有路由请求request的信息,也有返回的responseWriter里的信息等

由于信息过于杂碎,很多不重要的信息要重复机械地填写,如果不进行封装,会让代码看的拥挤冗长

设计context,可以将一些复杂的信息保留在context内部,对外进行路由处理的时候简化接口

day2-context/gee/context.go

package gee

import (
	"encoding/json"
	"fmt"
	"net/http"
)

type H map[string]interface{}

type Context struct {
	// origin objects
	Writer 		http.ResponseWriter
	Req   	   *http.Request
	// request info
	Path  		string
	Method 		string
	// response info
	StatusCode 	int
}

func newContext(w http.ResponseWriter, req *http.Request) *Context {
	return &Context{
		Writer:     w,
		Req:        req,
		Path:       req.URL.Path,
		Method:     req.Method,
	}
}

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

//URl可以理解为网址,例如 http://example.com:8080/path/to/resource?key1=value1&key2=value2#section1
func (c *Context) Query(key string) string {
	return c.Req.URL.Query().Get(key)
}

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

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

//上面的是一些封装好的工具,接下来要对string json html利用工具进行处理
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...)))
}

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)
	}
}

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

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

代码当中对状态码,头部信息等常用的填写,利用方法进行了封装,通过使用封装好的方法,来包装处理StringJSON等格式的信息

并且还提供了访问PostForm和Query的方法,提高的代码的扩展能力

在下文当中添加路由的时候,只需要调用String( )JSON( )等方法,输入状态码和我们想要返回给客户端的内容,就可以自动添加路由

路由

day2-context/gee/router.go

package gee

import (
	"fmt"
	"net/http"
)

type router struct {
	handlers map[string]HandlerFunc 
}

func newRouter() *router {
	return &router{handlers: make(map[string]HandlerFunc)}
}

func (r *router) addRoute(method string, pattern string, handler HandlerFunc) {
	key := method + "-" + pattern
	r.handlers[key] = handler
}

func (r *router) handle(c *Context) {
	key := c.Method + "-" + c.Path
	fmt.Println(key)
	if handler, ok := r.handlers[key]; ok {
		handler(c)
	} else {
		c.String(http.StatusNotFound, "404 NOT FOUND: %s\n", c.Path)
	}
}

通过addRoute方法可以添加路由进路由表当中

通过handle方法,会根据我们传入的context当中的信息,来查找路由表,调用对应的路由方法

框架入口

package gee

import (
	"log"
	"net/http"
)

// HandlerFunc defines the request handler used by gee
type HandlerFunc func(*Context)

// Engine implement the interface of ServeHTTP
type Engine struct {
	router *router
}

// New is the constructor of gee.Engine
func New() *Engine {
	return &Engine{router: newRouter()}
}

func (engine *Engine) addRoute(method string, pattern string, handler HandlerFunc) {
	log.Printf("Route %4s - %s", method, pattern)
	engine.router.addRoute(method, pattern, 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)
}

func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	c := newContext(w, req)
	engine.router.handle(c)
}
addRoute方法通过调用route里的addRoute来添加路由
type HandlerFunc func(*Context),HandlerFunc被我们改写成了一个参数为context的匿名函数
在调用GETPOST方法的时候,只需要传入我们的路径信息pattern和一个匿名函数,通过对函数的context参数利用context.go里封装好的方法来写入信息
类似于下面这样,就可以很轻松的达到添加路由的目的了

day2-context/main.go

package main
import (
	"net/http"
	"gee"
)

func main() {
	r := gee.New()
	r.GET("/", func(c *gee.Context) {
		c.HTML(http.StatusOK, "<h1>Hello 大沙包</h1>")
	})
	r.GET("/hello", func(c *gee.Context) {
		// expect /hello?name=大沙包
		c.String(http.StatusOK, "hello %s, you're at %s\n", c.Query("name"), c.Path)
	})
	
	
	r.POST("/login", func(c *gee.Context) {
		c.JSON(http.StatusOK, gee.H{
			"username": c.PostForm("username"),
			"password": c.PostForm("password"),
		})
	})

	r.Run(":9090")
}

运行之后,可以利用postman和curl等工具来进行验证

7.15号曾经写过这个帖子,后来忘记保存了,码了半天的字,图文并茂,很伤心,今天就简单写一下?

原帖链接