go web学习(四)
阅读原文时间:2023年07月08日阅读:1

跟着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)
    }
    )
}