• 怎么定义 Handler?
  • 怎么定义 Server?
  • 怎么定义 Middleware? 如何用?

目录

自定义 Handler

标准库http提供了Handler接口,用于开发者实现自己的handler。只要实现接口的ServeHTTP方法即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
type textHandler struct {
    responseText string
}

func (th *textHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, th.responseText)
}

func main() {
    mux := http.NewServeMux()

    mux.Handle("/", &textHandler{"你好呀!"})
    
    http.ListenAndServe(":8082", mux)
}

Note:Server 实例的 Handler 字段最后通过 mux 初始化

自定义 Server

使用 http.Server 创建自定义的 server 对象

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
func main() {
    mux := http.NewServeMux()

    http.HandleFunc("/", textHandler)

    server := &http.Server{
        Addr:         ":8082",
        ReadTimeout:  60 * time.Second,
        WriteTimeout: 60 * time.Second,
        Handler:      mux,
    }
    server.ListenAndServe()
}

中间件 Middleware

中间件:一般是指应用程序中封装原始信息,添加额外功能的组件。

  • 一个好的中间件拥有单一的功能, 可插拔并且是自我约束的

应用方向:

  • 通过隐藏长度缓解BREACH攻击
  • 频率限制
  • 屏蔽恶意自动程序
  • 提供调试信息
  • 添加HSTS, X-Frame-Options头
  • 从异常中优雅恢复
  • 以及其他等等。

前文的 HandleFunc 就能把签名为 func(w http.ResponseWriter, r *http.Reqeust)的函数包裹成handler。这个函数也算是中间件。

Go 的 HTTP 中间件很简单,只要实现一个函数签名为:func(http.Handler) http.Handler 的函数即可。

 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
30
31
32
33
34
package main

import (
	"fmt"
	"log"
	"net/http"
	"time"
)

func IndexHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "你好呀!")
}

func logger(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		log.Printf("starting %s %s\n", r.Method, r.URL.Path)
		next.ServeHTTP(w, r)
		log.Printf("finished %s in %v\n", r.URL.Path, time.Since(start))
	})
}

func hook(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		log.Println("before hook")
		next.ServeHTTP(w, r)
		log.Println("after hook")
	})
}

func main() {
	http.Handle("/hi", hook(logger(http.HandlerFunc(IndexHandler))))
	http.ListenAndServe(":8082", nil)
}

如上,函数调用形成了一条链,可以在这条链上做很多事情。loggerHandler 记录请求开始和完成时间,hook 又包裹了 loggerHandler 可以在日志记录之前做对应的处理。

See Also

Thanks to the authors 🙂

返回目录