Golang HTTP 消息中间件 简单实现

该博客围绕Go语言HTTP添加中间件展开。首先提出需求,即实现业务与非业务功能代码解耦,支持动态增删中间件。接着定义了HTTP路由相关函数,介绍了http.Handle和http.HandleFunc的区别。最后给出添加timeCost和Logger中间件的示例文件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 需求

  • 消息中间件可以将业务功能代码和非业务功能代码的解耦
  • 支持能够动态地增删中间件

2. HTTP路由相关函数定义

  • http.HandleFunc(pattern string, handler func(ResponseWriter, *Request))
  • http.Handle(pattern string, handler Handler)
  • http.Handle 第二个参数传递的是一个http.Handler接口,而http.HandleFunc第二个参数传递的是一个实现了func(ResponseWriter, *Request)的函数
// Handle registers the handler for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }

// HandleFunc registers the handler function for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}
  • http.HandlerFunc 是函数func(ResponseWriter, *Request)类型的变量,该变量实现了ServeHTTP接口,所以,可以通过http.HandlerFunc强制转换func(ResponseWriter, *Request)类型的函数,使其满足http.Handler接口
  • http.Handler 是接口,含有方法ServeHTTP
type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

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

 

3. 给http添加timeCost和Logger中间件

  • middleware.go
package main

import (
	"log"
	"net/http"
	"os"
	"time"
)

var Logger *log.Logger

type middleware func(handler http.Handler) http.Handler

type Router struct {
	MiddlewareChain []middleware
	Mux             map[string]http.Handler
}

func NewRouter() *Router {
	return &Router{Mux: make(map[string]http.Handler)}
}

func (r *Router) Use(mid middleware) {
	r.MiddlewareChain = append(r.MiddlewareChain, mid)
}

func (r *Router) Add(route string, handler http.Handler) {
	var mergeredHandler = handler
	for i := len(r.MiddlewareChain) - 1; i >= 0; i-- {
		mergeredHandler = r.MiddlewareChain[i](mergeredHandler)
	}
	Logger.Println("route:", route)
	Logger.Printf("handler %+v\n", handler)
	r.Mux[route] = mergeredHandler
}

func timeCost(handler http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		timeStart := time.Now()
		handler.ServeHTTP(w, r)
		timeElapsed := time.Since(timeStart)
		Logger.Println("time cost:", timeElapsed)
	})

}

func logger(handler http.Handler) http.Handler {
	Logger = log.New(os.Stdout, "", 0)
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		handler.ServeHTTP(w, r)
	})
}
  • main.go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	router := NewRouter()
	router.Use(middleware(logger))
	router.Use(middleware(timeCost))
	router.Add("/hello", http.HandlerFunc(Hello))

	http.Handle("/hello", router.Mux["/hello"])
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		Logger.Fatalln("Http listen error ", err.Error())
	}

	defer func() {
		if p := recover(); p != nil {
			Logger.Println("catch panic:", p)
		}
	}()
}

func Hello(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "%s\n", "hello boy")
}
  • output:
$ while true; do curl localhost:8080/hello; done
hello boy
hello boy
hello boy
hello boy
hello boy
hello boy
hello boy


$ go run main.go middleware.go 
route: /hello
handler 0x64eb90
time cost: 5.713µs
time cost: 5.621µs
time cost: 8.852µs
time cost: 5.478µs
time cost: 9.152µs
time cost: 7.512µs
time cost: 5.521µs
time cost: 46.754µs
time cost: 4.605µs
time cost: 9.383µs
time cost: 5.244µs
time cost: 19.858µs
time cost: 4.372µs
time cost: 16.27µs
time cost: 122.69µs
time cost: 4.319µs

 

 

消息中间件利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程间的通信。消息中间件适用于需要可靠的数据传送的分布式环境。采用消息中间件机制的系统中,不同的对象之间通过传递消息来激活对方的事件,完成相应的操作。发送者将消息发送给消息服务器,消息服务器将消息存放在若干队列中,在合适的时候再将消息转发给接收者。消息中间件能在不同平台之间通信,它常被用来屏蔽掉各种平台及协议之间的特性,实现应用程序之间的协同,其优点在于能够在客户和服务器之间提供同步和异步的连接,并且在任何时刻都可以将消息进行传送或者存储转发,这也是它比远程过程调用更进一步的原因。在了解消息中间件之前,首先了解两个基本概念Message和Queue。Message :消息“消息”是在两台计算机间传送的数据单位。消息可以非常简单,例如只包含文本字符串;也可以更复杂,可能包含嵌入对象。Queue:消息队列,用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。队列的主要目的是提供路由并保证消息的传递;如果发送消息时接收者不可用,消息队列会保留消息,直到可以成功地传递它。消息队列的主要特点是异步处理,主要目的是减少请求响应时间和解耦。所以主要的使用场景就是将比较耗时而且不需要即时(同步)返回结果的操作作为消息放入消息队列。同时由于使用了消息队列,只要保证消息格式不变,消息的发送方和接收方并不需要彼此联系,也不需要受对方的影响,即解耦和。这也是消息中间件的意义所在。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值