day02 | 上下文实现
上下文 | 屏蔽内部细节
简化处理细节 | 提高使用的便捷
-
每一次对于
Web服务请求,主要是访问和响应,体现在程序上就是ResponseWriter和*Request.在这个互联请求过程还有很多其余信息,例如Request信息// go官方 Request结构体 type Request struct { Method string URL *url.URL Proto string // "HTTP/1.0" ProtoMajor int // 1 ProtoMinor int // 0 Header Header Body io.ReadCloser GetBody func() (io.ReadCloser, error) ContentLength int64 TransferEncoding []string Close bool Host string Form url.Values PostForm url.Values MultipartForm *multipart.Form Trailer Header RemoteAddr string RequestURI string TLS *tls.ConnectionState Cancel <-chan struct{} Response *Response ctx context.Context } -
我们没必要每一次传递输入和输出信息,只需要设置一个结构体和定义一组方法,来实现彼此间的交互,具体传入的参数可以是我们自己指定的.习惯上,把这样的结构体成为
Context -
这样一来,对外只需要暴露接口,简化了使用的复杂度.要求我们在内部实现即可
Context内部实现
ConText结构体
-
我们对于
Context可以先补充部分信息,例如type Context struct { // 在之前的使用里面 这两个 用w 和 r代替 // 接受到和要处理的 Writer http.ResponseWriter Req *http.Request Path, Method string StatusCode int }
Context实现的方法
-
newContext
func newContext(w http.ResponseWriter, r *http.Request) *Context { return &Context{ Writer: w, Req: r, Path: r.URL.Path, Method: r.Method, } } -
PostForm
// PostForm 直接调用FormValue 以下类似 func (c *Context) PostForm(key string) string { return c.Req.FormValue(key) } -
Query
// Query 中调用GET方法 // Get gets the first value associated with the given key. // If there are no values associated with the key, Get returns // the empty string. To access multiple values, use the map // directly. func (c *Context) Query(key string) string { return c.Req.URL.Query().Get(key) } -
Status
// Status 调用WriteHeader 方法 // WriteHeader sends an HTTP response header with the provided // status code. func (c *Context) Status(code int) { c.StatusCode = code c.Writer.WriteHeader(code) } -
SetHeader
// SetHeader 一下方法实现 同上思路 func (c *Context) SetHeader(key, value string) { c.Writer.Header().Set(key, value) } -
String | JSON |Data | HTML
func (c *Context) String(code int, format string, values ...interface{}) { // 调用刚写好的方法 c.SetHeader("Content-Type", "text/plain") c.Status(code) // 格式化 fmt.Sprintf的两个参数 format string, a ...any 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) val := json.NewEncoder(c.Writer) if err := val.Encode(obj); err != nil { // http.Error所需要的参数 w ResponseWriter, error string, code int http.Error(c.Writer, err.Error(), 500) } } func (c *Context) Data(code int, data []byte) { c.Status(code) // http.ResponseWriter 需要给回复的信息 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)) }
优化Engine | 在实现上下文的基础上
- 只是在部分函数上进行优化处理即可
Engine结构体
-
我们对于
Engine可以直接存储router指针 -
HandleFunc可以直接由*Context代替http.ResponseWriter,和*http.Request简化实现// 处理函数 type HandleFunc func(*Context) type Engine struct { router *router }
Engine实现的方法
-
New
func New() *Engine { return &Engine{router: newRounter()} } -
GET和POST方法不需要改变
// get方法实现 func (engine *Engine) GET(pattern string, handler HandleFunc) { engine.addRoute("GET", pattern, handler) } // post方法实现 func (engine *Engine) POST(pattern string, handler HandleFunc) { engine.addRoute("POST", pattern, handler) } -
ServeHTTP | handler中的接口方法
// run 开始运行 func (engine *Engine) Run(addr string) (err error) { return http.ListenAndServe(addr, engine) } // 直接给出上下文环境 让路由自己实现的 handle 方法 处理上下文 即可 func (engine *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) { c := newContext(w, r) engine.router.handle(c) }
Router| 路由设置
- 优化处理了一下 上下文 ,自然在 建立路由过程之中,首要的实现绑定路由 其次是处理方法
HandleFunc
Router 结构体
-
我们对于
router先完善最重要的信息,路径和实现方法type router struct { handlers map[string]HandleFunc }
Router 实现的方法
-
newRounter | 建立新的路由
func newRounter() *router { return &router{handlers: make(map[string]HandleFunc)} } -
addRouter | 增加路由
func (r *router) addRouter(method, pattern string, handler HandleFunc) { key := method + "-" + pattern r.handlers[key] = handler } -
handle | 进行路由匹配,如果不存在则表示
404func (r *router) handle(c *Context) { // 对应上文的 key := c.Method + "-" + c.Path if handler, err := r.handlers[key]; err { handler(c) } else { c.String(http.StatusNotFound, "404 NOT FOUND:%s \n", c.Path) } }
完整代码比较长 | 存储于Github仓库