HTTP基础

181 阅读2分钟

对于GO中的HTTP内置包,有一些需要避坑的点,博主写在另一篇文章中,那篇文章中需要避免的坑对我们在设计自己的Web框架有很大的好处,尤其是对于上下文。

启动服务

方式一

package main

import "net/http"

func main() {
    // 将路由和视图函数进行绑定
    http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
            w.WriteHeader(http.StatusOK)
            _, _ = w.Write([]byte("user home"))
    })

    // 启动服务器,第二个参数是nil表示用net/http内置的默认的IO多路复用器
    _ = http.ListenAndServe(":8080", nil)
}

方式二

package main

import "net/http"

func main() {
    // 初始化一个复用器
    mux := http.NewServeMux()
    mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
            w.WriteHeader(http.StatusOK)
            _, _ = w.Write([]byte("user home"))
    })
    http.Handle("/user", mux)
    _ = http.ListenAndServe(":8080", mux)
}

方式三

我们由方式二得出灵感,自定义一个结构体实现Handler接口就能充当一个IO多路复用器。并且Handler接口要求需要实现ServeHTTP方法即可。

image.png

package main

import (
    "fmt"
    "net/http"
)

type Engine struct{}

func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    url := r.URL.Path
    switch url {
    case "/user":
            w.WriteHeader(http.StatusOK)
            _, _ = w.Write([]byte(fmt.Sprintf("hello %s", url)))
    case "/order":
            w.WriteHeader(http.StatusOK)
            _, _ = w.Write([]byte(fmt.Sprintf("hello %s", url)))
    default:
            w.WriteHeader(http.StatusNotFound)
            _, _ = w.Write([]byte("NOT FOUND"))
            return
    }
}

func NewEngine() *Engine {
    return &Engine{}
}

func main() {
    engine := NewEngine()
    _ = http.ListenAndServe(":8080", engine)
}

框架雏形

在具体实现neo框架雏形的时候,我们需要先思考几个问题。【可以对比Gin框架】

  1. 路由存在什么地方
  2. 路由怎么注册
  3. 路由怎么匹配
  4. Web服务怎么启动
  5. Web服务支持那些请求方式
package neo

import (
    "fmt"
    "net/http"
)

// HandlerFunc 视图函数签名
type HandlerFunc func(w http.ResponseWriter, r *http.Request)

type Engine struct {
    router map[string]HandlerFunc // 路由和视图作绑定【key是路由,value是视图函数】
}

// 内部核心API,仅共内部使用,用于注册路由
func (e *Engine) addRouter(method string, pattern string, handlerFunc HandlerFunc) {
    key := fmt.Sprintf("%s-%s", method, pattern)
    e.router[key] = handlerFunc
}

// GET 外部衍生API,提供给用户使用
func (e *Engine) GET(pattern string, handlerFunc HandlerFunc) {
    e.addRouter(http.MethodGet, pattern, handlerFunc)
}
func (e *Engine) POST(pattern string, handlerFunc HandlerFunc) {
    e.addRouter(http.MethodPost, pattern, handlerFunc)
}
func (e *Engine) DELETE(pattern string, handlerFunc HandlerFunc) {
    e.addRouter(http.MethodDelete, pattern, handlerFunc)
}
func (e *Engine) PUT(pattern string, handlerFunc HandlerFunc) {
    e.addRouter(http.MethodPut, pattern, handlerFunc)
}

// 对外对接用户,对内对接Web框架
func (e *Engine) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    // 请求来了,需要匹配路由
    url := r.URL.Path
    method := r.Method
    key := fmt.Sprintf("%s-%s", method, url)
    handlerFunc, ok := e.router[key]
    if !ok {
            w.WriteHeader(http.StatusNotFound)
            _, _ = w.Write([]byte("NOT FOUND"))
            return
    }
    // 执行命中的视图函数
    handlerFunc(w, r)
}

// Run 手动启动服务,控制力强
func (e *Engine) Run(addr string) error {
    return http.ListenAndServe(addr, e)
}

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