跟着b站https://space.bilibili.com/361469957 杨旭老师学习做的笔记
请求————> 中间件 ————> Handler
响应 <———— Middleware <———— Handler
func ListenAndServe(addr string, handler Handler) error
handler 如果是 nil:DefaultServeMux
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
type MyMiddleware struct {
Next http.Handler
}
func(m MyMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 在 next handler 之前做一些事情
m.Next.ServeHTTP(w, r)
// 在 next handler 之后做一些事情
}
Logging
安全
请求超时
响应压缩
…
下面是例子
// 目录下
// middleware文件夹 包含auth.go
// main.go
auth.go
package middleware
import "net/http"
// 链式结构, Next 设置为 什么,下一个handler 就是什么
// AuthMiddleware ..
type AuthMiddleware struct {
Next http.Handler
}
func (am *AuthMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 如果只有一个中间件,改中间件的字段next 为nil, 交给默认路由器处理
if am.Next == nil {
am.Next = http.DefaultServeMux
}
// 判断auth
auth := r.Header.Get("Authorization")
if auth != "" {
// before 路由
am.Next.ServeHTTP(w, r)
// after 路由
} else {
w.WriteHeader(http.StatusUnauthorized)
}
}
main.go
package main
import (
"encoding/json"
"net/http"
"timer/goWeb-sql/middleware"
//middleware文件夹的位置,每个人都不一样,自己建的
)
type Company struct {
ID int
Name string
Country string
}
func main(){
http.HandleFunc("/companies", func(w http.ResponseWriter, r *http.Request){
c := Company{
ID: 123,
Name: "goolle",
Country: "USA",
}
// time.Sleep(4*time.Second)
enc := json.NewEncoder(w)
enc.Encode(c)
})
// 通过认证就能获取数据
// 使用中间件
http.ListenAndServe("localhost:8080", new(middleware.AuthMiddleware))
}
GET http://localhost:8080/companies HTTP/1.1
# with auth
GET http://localhost:8080/companies HTTP/1.1
Authorization: root
这个是加上请求上下文的
// 目录下
// middleware文件夹 包含auth.go timeout.go
// main.go
timeout.go
package middleware
import (
"context"
"net/http"
"time"
)
type TimeoutMiddleware struct {
Next http.Handler
}
func (tm TimeoutMiddleware) ServeHTTP(w http.ResponseWriter ,r *http.Request){
if tm.Next == nil{
tm.Next = http.DefaultServeMux
}
ctx:= r.Context()
ctx,_ = context.WithTimeout(ctx,3*time.Second)
r.WithContext(ctx)
ch:= make(chan struct{})
go func(){
tm.Next.ServeHTTP(w,r)
ch <- struct{}{}
}()
select{
case <- ch:
return
case<- ctx.Done():
w.WriteHeader(http.StatusRequestTimeout)
}
ctx.Done()
}
main.go
http.HandleFunc("/companies", func(w http.ResponseWriter, r *http.Request) {
c := Company{
ID: 123,
Name: "gggoolle",
Country: "USA",
}
// time.Sleep(4*time.Second) 用来测试的
enc := json.NewEncoder(w)
enc.Encode(c)
})
// 使用中间件
http.ListenAndServe("localhost:8080", &middleware.TimeoutMiddleware{
Next: new(middleware.AuthMiddleware),
})
(例子见上面那个)
请求可能会通过中间件,到达handler,再到model层(数据库,Web Api,文件系统),model层不应该知道在web请求的上下文操作,但是他们需要知道一些重要信息,比如超时停摆。
它可以用于在不同的 Goroutine 之间传递请求特定值、取消信号以及超时截止日期等数据,以协调 Goroutine 之间的操作。
func(*Request) Context() context.Context
返回当前请求的上下文
func(*Request) WithContext(ctx context.Context) context.Context
基于 Context 进行“修改”,(实际上)创建一个新的 Context
type Context interface {
Deadline() (deadline time.Time, ok bool)
//返回 完成工作的截止日期
Done() <-chan struct{}
//返回一个 Channel,这个 Channel 会在当前工作完成或者上下文被取消后关闭,
//多次调用 Done 方法会返回同一个 Channel
Err() error
// 错误
Value(key interface{}) interface{}
// 从 context.Context中获取键对应的值
}
//这些方法都是用于读取,不能进行设置
WithCancel(),它有一个 CancelFunc
WithDeadline(),带有一个时间戳(time.Time)
WithTimeout(),带有一个具体的时间段(time.Duration)
WithValue(),在里面可以添加一些值
诸如日志,安全检查和错误处理,为了防止代码重复和代码依赖,可以使用串联技术分隔它们。
也叫做管道处理
输入——》f1 do something ——》f2 do something ——》f3 do something ——》输出
和中间件相像又不一样
// http.HandleFunc("/hello",protect(log(hello)))
func hello(w http.ResponseWriter,r *http.Request){
//
}
func log(h http.HandlerFunc) http.HandlerFunc{
return func(w http.ResponseWriter,r *http.Request){
//日志操作
h(w,r)
}
}
func protect(h http.HandlerFunc) http.HandlerFunc{
return func(w http.ResponseWriter,r *http.Request){
//一些操作
h(w,r)
}
}
// http.Handle("/hello",protect(log(hello)))
type HelloHandler struct{}
func (h HelloHandler) ServeHttp (w http.ResponseWriter,r *http.Request){
}
func log(h HelloHandler) http.Handler{
return http.HandlerFunc(
func(w http.ResponseWriter,r *http.Request){
//一些操作
h.ServeHttp(w,r)
}
)
}
func protectlog(h HelloHandler) http.Handler{
return http.HandlerFunc(
func(w http.ResponseWriter,r *http.Request){
//一些操作
h.ServeHttp(w,r)
}
)
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章