go web学习(四)

跟着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 之间的操作。

request Context

func(*Request) Context() context.Context
返回当前请求的上下文
func(*Request) WithContext(ctx context.Context) 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中获取键对应的值
  }
//这些方法都是用于读取,不能进行设置

Context API – 可以返回新 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)
    }
    )
}
posted @ 2023-05-22 12:18  id_shiguang  阅读(10)  评论(0编辑  收藏  举报