go-Web框架实现02
go-Web框架实现 | 笔记整理!
day02 | 上下文实现
上下文 | 屏蔽内部细节
简化处理细节 | 提高使用的便捷
每一次对于
Web服务
请求,主要是访问
和响应
,体现在程序上就是ResponseWriter
和*Request
.在这个互联请求过程还有很多其余信息,例如Request
信息1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25// 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
可以先补充部分信息,例如1
2
3
4
5
6
7
8
9
10type Context struct {
// 在之前的使用里面 这两个 用w 和 r代替
// 接受到和要处理的
Writer http.ResponseWriter
Req *http.Request
Path, Method string
StatusCode int
}
Context实现的方法
newContext
1
2
3
4
5
6
7
8func newContext(w http.ResponseWriter, r *http.Request) *Context {
return &Context{
Writer: w,
Req: r,
Path: r.URL.Path,
Method: r.Method,
}
}PostForm
1
2
3
4// PostForm 直接调用FormValue 以下类似
func (c *Context) PostForm(key string) string {
return c.Req.FormValue(key)
}Query
1
2
3
4
5
6
7
8// 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
1
2
3
4
5
6
7// 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
1
2
3
4// SetHeader 一下方法实现 同上思路
func (c *Context) SetHeader(key, value string) {
c.Writer.Header().Set(key, value)
}String | JSON |Data | HTML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30func (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
简化实现1
2
3
4
5
6// 处理函数
type HandleFunc func(*Context)
type Engine struct {
router *router
}
Engine实现的方法
New
1
2
3func New() *Engine {
return &Engine{router: newRounter()}
}GET和POST方法不需要改变
1
2
3
4
5
6
7
8
9// 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中的接口方法
1
2
3
4
5
6
7
8
9
10// 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
先完善最重要的信息,路径
和实现方法
1
2
3type router struct {
handlers map[string]HandleFunc
}
Router 实现的方法
newRounter | 建立新的路由
1
2
3func newRounter() *router {
return &router{handlers: make(map[string]HandleFunc)}
}addRouter | 增加路由
1
2
3
4func (r *router) addRouter(method, pattern string, handler HandleFunc) {
key := method + "-" + pattern
r.handlers[key] = handler
}handle | 进行路由匹配,如果不存在则表示
404
1
2
3
4
5
6
7
8
9func (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仓库