zoukankan      html  css  js  c++  java
  • GO-中间件(Middleware )

    中间件是一种计算机软件,可为操作系统提供的软件应用程序提供服务,以便于各个软件之间的沟通,特别是系统软件和应用软件。广泛用于web应用和面向服务的体系结构等。

    纵观GO语言,中间件应用比较普遍,主要应用:

    • 记录对服务器发送的请求(request)
    • 处理服务器响应(response )
    • 请求和处理之间做一个权限认证工作
    • 远程调用
    • 安全
    • 等等

    中间件处理程序是简单的http.Handler,它包装另一个http.Handler做请求的一些预处理和/或后处理。它被称为“中间件”,因为它位于Go Web服务器和实际处理程序之间的中间位置。

    下面是一些中间件例子

    记录日志中间件

    package main
    
    import (
       "fmt"
       "log"
       "net/http"
    )
    
    func logging(f http.HandlerFunc) http.HandlerFunc {
       return func(w http.ResponseWriter, r *http.Request) {
          log.Println(r.URL.Path)
          f(w, r)
       }
    }
    func foo(w http.ResponseWriter, r *http.Request) {
       fmt.Fprintln(w, "foo")
    }
    
    func bar(w http.ResponseWriter, r *http.Request) {
       fmt.Fprintln(w, "bar")
    }
    
    func main() {
       http.HandleFunc("/foo", logging(foo))
       http.HandleFunc("/bar", logging(bar))
       http.ListenAndServe(":8080", nil)
    }
    

      

    访问 http://localhost:8080/foo

    返回结果

    foo
    

     

    终端打印

    2020/05/16 22:56:10 /foo
    

      

    将上面示例修改下,也可以实现相同的功能。

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    )
    
    func foo(w http.ResponseWriter, r *http.Request) {
    	fmt.Fprintln(w, "foo")
    }
    func bar(w http.ResponseWriter, r *http.Request) {
    	fmt.Fprintln(w, "bar")
    }
    
    func loggingMiddleware(next http.Handler) http.Handler {
    	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    		log.Println(r.URL.Path)
    		next.ServeHTTP(w, r)
    	})
    }
    
    func main() {
    
    	http.Handle("/foo", loggingMiddleware(http.HandlerFunc(foo)))
    	http.Handle("/bar", loggingMiddleware(http.HandlerFunc(bar)))
    	http.ListenAndServe(":8080", nil)
    }
    

      

    访问 http://localhost:8080/foo

    返回结果

    foo
    

     

    终端打印

    2020/05/16 22:56:10 /foo

     

    多中间件例子

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/http"
    	"time"
    )
    
    type Middleware func(http.HandlerFunc) http.HandlerFunc
    
    // Logging logs all requests with its path and the time it took to process
    func Logging() Middleware {
    	// Create a new Middleware
    	return func(f http.HandlerFunc) http.HandlerFunc {
    		// Define the http.HandlerFunc
    		return func(w http.ResponseWriter, r *http.Request) {
    			// Do middleware things
    			start := time.Now()
    			defer func() { log.Println(r.URL.Path, time.Since(start)) }()
    			// Call the next middleware/handler in chain
    			f(w, r)
    		}
    	}
    }
    
    // Method ensures that url can only be requested with a specific method, else returns a 400 Bad Request
    func Method(m string) Middleware {
    	// Create a new Middleware
    	return func(f http.HandlerFunc) http.HandlerFunc {
    		// Define the http.HandlerFunc
    		return func(w http.ResponseWriter, r *http.Request) {
    			// Do middleware things
    			if r.Method != m {
    				http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
    				return
    			}
    			// Call the next middleware/handler in chain
    			f(w, r)
    		}
    	}
    }
    
    // Chain applies middlewares to a http.HandlerFunc
    func Chain(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
    	for _, m := range middlewares {
    		f = m(f)
    	}
    	return f
    }
    
    func Hello(w http.ResponseWriter, r *http.Request) {
    	fmt.Fprintln(w, "hello world")
    }
    
    func main() {
    	http.HandleFunc("/", Chain(Hello, Method("GET"), Logging()))
    	http.ListenAndServe(":8080", nil)
    }
    

      

    访问 http://localhost:8080

    返回结果

    hello world
    

     

    终端打印

    2020/05/16 23:00:26 / 28.601µs
    

      

    中间件本身只是将其http.HandlerFunc作为其参数之一,包装它并返回一个新http.HandlerFunc的服务器来调用。在这里,我们定义了一种新类型Middleware,最终可以更容易地将多个中间件链接在一起。

     

    当然我们也可以改成如下形式

    package main
    
    import (
       "fmt"
       "log"
       "net/http"
       "time"
    )
    
    type Middleware func(http.Handler) http.Handler
    
    func Hello(w http.ResponseWriter, r *http.Request) {
       fmt.Fprintln(w, "hello world")
    }
    
    func Chain(f http.Handler, mmap ...Middleware) http.Handler {
       for _, m := range mmap {
          f = m(f)
       }
       return f
    }
    func Method(m string) Middleware {
       return func(f http.Handler) http.Handler {
          return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
             log.Println(r.URL.Path)
             if r.Method != m {
                http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
                return
             }
             f.ServeHTTP(w, r)
          })
       }
    
    }
    func Logging() Middleware {
       return func(f http.Handler) http.Handler {
          return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
             //log.Println(r.URL.Path)
             // Do middleware things
             start := time.Now()
             defer func() { log.Println(r.URL.Path, time.Since(start)) }()
             f.ServeHTTP(w, r)
          })
       }
    }
    
    func main() {
       http.Handle("/", Chain(http.HandlerFunc(Hello), Method("GET"), Logging()))
       http.ListenAndServe(":8080", nil)
    }
    

      

    在gin框架下实现中间件

    r := gin.Default() 创建带有默认中间件的路由,默认是包含logger和recovery中间件的
    r :=gin.new()      创建带有没有中间件的路由
    

    示例

    package main
    
    import (
    	"github.com/gin-gonic/gin"
    	"log"
    	"time"
    )
    
    func Logger() gin.HandlerFunc {
    	return func(c *gin.Context) {
    		t := time.Now()
    		// Set example variable
    		c.Set("example", "12345")
    		// before request
    		c.Next()
    		// after request
    		latency := time.Since(t)
    		log.Print(latency) //时间  0s
    		// access the status we are sending
    		status := c.Writer.Status()
    		log.Println(status) //状态 200
    	}
    }
    func main() {
    	r := gin.New()
    	r.Use(Logger())
    
    	r.GET("/test", func(c *gin.Context) {
    		example := c.MustGet("example").(string)
    		// it would print: "12345"
    		log.Println(example)
    		c.JSON(200, gin.H{"code": 200})
    	})
    	// Listen and serve on 0.0.0.0:8080
    	r.Run(":8080")
    }
    

      

    访问 http://localhost:8080

    返回结果

    {"code":200}
    

       

    终端打印

    2020/05/16 23:07:34 12345
    2020/05/16 23:07:34 245.296µs
    2020/05/16 23:07:34 200
    

      

    以上示例也可改为

    package main
    
    import (
    	"github.com/gin-gonic/gin"
    	"log"
    	"time"
    )
    
    func Logger() gin.HandlerFunc {
    	return func(c *gin.Context) {
    		t := time.Now()
    		// Set example variable
    		c.Set("example", "12345")
    		// before request
    		c.Next()
    		// after request
    		latency := time.Since(t)
    		log.Print(latency) //时间  0s
    		// access the status we are sending
    		status := c.Writer.Status()
    		log.Println(status) //状态 200
    	}
    }
    
    func main() {
    	r := gin.New()
    	r.GET("/test", Logger(), func(c *gin.Context) {
    		example := c.MustGet("example").(string)
    		// it would print: "12345"
    		log.Println(example)
    		c.JSON(200, gin.H{"code": 200})
    	})
    	// Listen and serve on 0.0.0.0:8080
    	r.Run(":8080")
    }
    

      

    Songzhibin
  • 相关阅读:
    iBatisnet 1.5版本的配置文件的几个变化
    使用Trace时要注意
    无刷新转页面?
    无刷新“页面跳转”问题一:与AtlasToolKit协同工作
    Assembly的Release与Debug
    iBatis.Net系列(四) iBatisNet API基础
    Atlas 调用web service
    无刷新“页面跳转”
    iBatis.Net系列(六) ResultMap
    在GridView中格式化时间字段
  • 原文地址:https://www.cnblogs.com/binHome/p/12902766.html
Copyright © 2011-2022 走看看