go使用net/http 创建middleware中间件

在上一节文章 go使用net/http 创建web服务器-高阶篇
我们学会了创建 服务器。
在一般的C/S架构中,在多个客户端与服务器进行通信时,我们经常使用中间件,来出来一些,在业务逻辑之前的,客户端发送给服务器的数据验证。

一、什么是http中间件

在互联网的http通信中,如果多个客户端访问服务器,我们就会构建一个 client/server 客户端/服务器 架构来实现。
服务器用来接受客户端的请求,然后返回特定的资源或者数据给客户端。

中间件是客户端请求到达处理方法之前对其进行预处理的一些逻辑。
常用的应用场景有:

  1. 客户端身份校验
  2. 用户鉴权
  3. 客户端对服务器提供的特定服务是否有访问权限
  4. 验证用户 session,并保持通信存活
  5. 客户端请求参数解密
  6. 客户端参数格式化
  7. 日志记录器,用于记录每个 REST API 访问请求
  8. 跨域配置
  9. 返回数据格式化
  10. Header设置

二、中间件原理

在 Go 语言中,中间件 Handler 是封装另一个 http.Handler 以对请求进行预处理或后续处理的 http.Handler。它介于 Go Web 服务器与实际的处理程序之间,因此被称为“中间件”。
image.png

原理分析:
我们先看一个最简单的一个http服务器

package main

import (
    "fmt"
    "net/http"
)

func index(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintln(w, "Hello World")
}

func main() {
    http.HandleFunc("/index", index)
    http.ListenAndServe(":8090", nil)
}

上面的示例代码就实现了一个 http服务器。
在路由的处理方面,主要是 通过http.HandleFunc函数,我们可以看一下官方的源代码

// HandleFunc registers the handler function for the given pattern
// HandleFunc 注册handler处理函数到DefaultServeMux,用来绑定给定的url
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
// ServeMux文档有详细的url解析匹配介绍
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    DefaultServeMux.HandleFunc(pattern, handler)
}

// HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
    if handler == nil {
        panic("http: nil handler")
    }
    mux.Handle(pattern, HandlerFunc(handler))
}

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

我们可以看到最后的处理是通过 HandlerFunc 反射。
这个正是我们传过去的index(w http.ResponseWriter, r *http.Request)

三、代码实现 middleware中间件

我们实现了一个 简单的 中间件日志 代码如下:

package main

import (
    "fmt"
    "log"
    "net/http"
)

// middlewareLog中间件日志,用来记录每个请求,写进日子
func middlewareLog(handler http.HandlerFunc) http.HandlerFunc {
    return func(writer http.ResponseWriter, request *http.Request) {
        // 日志中间件
        log.Println(request.Header)
        handler(writer, request)
    }
}

func index(w http.ResponseWriter, r *http.Request) {
    _, _ = fmt.Fprintln(w, "Hello World")
}

func main() {
    http.HandleFunc("/index", middlewareLog(index))
    _ = http.ListenAndServe(":8090", nil)
}

与黑夜里,追求那一抹萤火。

60 声望
20 粉丝
0 条评论
推荐阅读
go语法入门-any类型的使用场景与注意
在没有any类型之前,go语言中,我们经常使用interface{},来表示一个类型是未知的,或者有好几种其他基础类型的情况。从 Go1.18开始,go官方定义了一个预声明标识符(Predeclared identifiers):any。

海生阅读 825

数据结构与算法:二分查找
一、常见数据结构简单数据结构(必须理解和掌握)有序数据结构:栈、队列、链表。有序数据结构省空间(储存空间小)无序数据结构:集合、字典、散列表,无序数据结构省时间(读取时间快)复杂数据结构树、 堆图二...

白鲸鱼9阅读 6.5k

「刷起来」Go必看的进阶面试题详解
逃逸分析是Go语言中的一项重要优化技术,可以帮助程序减少内存分配和垃圾回收的开销,从而提高程序的性能。下面是一道涉及逃逸分析的面试题及其详解。

王中阳Go4阅读 1.9k评论 1

封面图
初学后端,如何做好表结构设计?
这篇文章介绍了设计数据库表结构应该考虑的4个方面,还有优雅设计的6个原则,举了一个例子分享了我的设计思路,为了提高性能我们也要从多方面考虑缓存问题。

王中阳Go4阅读 1.7k评论 2

封面图
滚蛋吧,正则表达式!
你是不是也有这样的操作,比如你需要使用「电子邮箱正则表达式」,首先想到的就是直接百度上搜索一个,然后采用 CV 大法神奇地接入到你的代码中?

良许4阅读 2.2k

又一款眼前一亮的Linux终端工具!
今天给大家介绍一款最近发现的功能十分强大,颜值非常高的一款终端工具。这个神器我是在其他公众号文章上看到的,但他们都没把它的强大之处介绍明白,所以我自己体验一波后,再向大家分享自己的体验。

良许5阅读 1.8k

一分钟搞明白!快速掌握 Go WebAssembly
最近因为各种奇怪的原因,更多的接触到了 WebAssembly。虽然之前很多博客也翻过写过各种文章,但总感觉欠些味道。于是今天梳理了一版,和大家一起展开学习。

煎鱼4阅读 2.1k

与黑夜里,追求那一抹萤火。

60 声望
20 粉丝
宣传栏