Go Web 编程入门:中间件

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 中间件通常位于前端的客户端站点请求和请求的后端资源之间。中间件非常有用,尤其是当我们希望在进行 API 调用之前进行一些验证,例如请求方法、标头和 JWT 等。

前言

中间件通常位于前端的客户端站点请求和请求的后端资源之间。中间件非常有用,尤其是当我们希望在进行 API 调用之前进行一些验证,例如请求方法、标头和 JWT 等。

网络异常,图片无法展示
|


日志中间件


http.Handler 包装器是一个具有一个输入参数和一个输出参数的函数,两者都是 http.Handler 类型。

func Middleware(next http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        //code before make the backend api call
  next.ServeHTTP(w, r) //serve and handle the http request
        //code after make the backend api call
  })
}

现在,而不是直接服务和监听我们的 http 处理程序,例如:

http.ListenAndServe(":3000", handler)

我们现在可以将它包装在我们的中间件中并变成:

http.ListenAndServe(":3000", Middleware(handler))


接下来将介绍如何创建一个 Go 语言的日志中间件。


中间件只需将 http.HandlerFunc 作为其参数之一,将其包装并返回一个新的 http.HandlerFunc 供服务器调用。


新建一个 main.go 文件:

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


创建 mod 文件:

$ go mod init main.go 
go: creating new go.mod: module main.go
go: to add module requirements and sums:
        go mod tidy


打开另一个终端:

$ curl -s http://localhost:8080/foo
foo
$ curl -s http://localhost:8080/bar
bar
$ curl -s http://localhost:8080/foo\?bar
foo

运行上述代码:

$ go run main.go         
2022/05/25 23:12:00 /foo
2022/05/25 23:12:09 /bar
2022/05/25 23:12:16 /foo


中间件框架

中间件本身只是将 a 作为其参数之一,将其包装并返回一个新的供服务器调用。在这里,我们定义了一种新类型,它最终使将多个中间件链接在一起变得更加容易。这个想法的灵感来自于 Mat Ryers 关于构建 API 的演讲。

这个片段详细解释了如何创建一个新的中间件。在下面的完整示例中,代码结构示例如下:

func createNewMiddleware() Middleware {
    // Create a new Middleware
    middleware := func(next http.HandlerFunc) http.HandlerFunc {
        // Define the http.HandlerFunc which is called by the server eventually
        handler := func(w http.ResponseWriter, r *http.Request) {
            // ... do middleware things
            // Call the next middleware/handler in chain
            next(w, r)
        }
        // Return newly created handler
        return handler
    }
    // Return newly created middleware
    return middleware
}

完整测试

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

运行代码:

$ go run main.go 

打开另外的终端:

$ curl -s http://localhost:8080/
hello world
$ curl -s -XPOST http://localhost:8080/
Bad Request
$ go run main.go         
2022/05/25 23:20:01 / 21.595µs
2022/05/25 23:20:13 / 5.129µs
相关文章
|
24天前
|
自然语言处理 Java 数据库连接
掌握JSP页面编程:动态生成Web内容
【4月更文挑战第3天】Java Server Pages (JSP) 是一种用于创建动态Web内容的Java技术,它结合HTML并允许在页面中嵌入Java代码。JSP支持代码片段、表达式语言(EL)和JSTL标签库,简化动态内容生成。当服务器接收到请求时,执行JSP中的Java代码并将结果嵌入HTML返回给客户端。示例展示了如何显示当前日期和时间。JSP可与Servlet、JavaBeans、数据库等结合,用于构建功能丰富的交互式Web应用。
掌握JSP页面编程:动态生成Web内容
|
1月前
|
负载均衡 Java 中间件
使用Go语言构建高性能Web服务
Go语言作为一种快速、高效的编程语言,其在构建高性能Web服务方面具有独特优势。本文将探讨如何利用Go语言开发和优化Web服务,以实现更高的性能和可伸缩性。
|
1天前
|
SQL 关系型数据库 MySQL
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
Golang数据库编程详解 | 深入浅出Go语言原生数据库编程
|
3天前
|
设计模式 存储 前端开发
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
|
3天前
|
开发框架 前端开发 数据库
Python从入门到精通:3.3.2 深入学习Python库和框架:Web开发框架的探索与实践
Python从入门到精通:3.3.2 深入学习Python库和框架:Web开发框架的探索与实践
|
3天前
|
编译器 Go 开发者
Go语言入门|包、关键字和标识符
Go语言入门|包、关键字和标识符
22 0
|
11天前
|
域名解析 Linux PHP
[CTF]ctfshow web入门
[CTF]ctfshow web入门
|
11天前
|
前端开发 搜索推荐 数据安全/隐私保护
HTML标签详解 HTML5+CSS3+移动web 前端开发入门笔记(四)
HTML标签详解 HTML5+CSS3+移动web 前端开发入门笔记(四)
18 1
N..
|
1月前
|
JavaScript 前端开发 PHP
web编程的正则表达式
web编程的正则表达式
N..
10 1
|
1月前
|
安全 测试技术 网络安全
Web安全基础入门+信息收集篇
学习信息收集,针对域名信息,解析信息,网站信息,服务器信息等;学习端口扫描,针对端口进行服务探针,理解服务及端口对应关系;学习WEB扫描,主要针对敏感文件,安全漏洞,子域名信息等;学习信息收集方法及实现安全测试,能独立理解WEB架构框架,树立渗透测试开展思路!
18 0
Web安全基础入门+信息收集篇