Golang闭包代码解析 - 书中讲解不够清晰求解答

Golang闭包代码解析 - 书中讲解不够清晰求解答

package main

import (
	"fmt"
	"net/http"
)

func testHandlerFunc(w http.ResponseWriter, r *http.Request) {
	fmt.Println("Printing from testHandlerFunc")
	w.Write([]byte("From testHandlerFunc\n"))
}

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

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		fmt.Println("Executing before request phase")

		testHandlerFunc(w, r)  // 这是在做什么?

		handler.ServeHTTP(w, r)

		fmt.Println("Executing after response phase")
	})
}

func mainLogic(w http.ResponseWriter, r *http.Request) {
	fmt.Println("Executing mainLogic")
	w.Write([]byte("OK"))
}

func main() {

	mainLogicHandler := http.HandlerFunc(mainLogic)  // 我不完全理解为什么要把"mainLogic"放入http.HandlerFunc()类型中
	http.Handle("/", middleware(mainLogicHandler))  // 这个我理解
}

这段代码可以运行,我理解使用闭包的意义。你可以使用函数将不同的代码片段链接在一起。我大概明白发生了什么,但书中的解释不是很清楚。我知道这是一个非常开放性的问题,我只是想彻底理解这个概念。


更多关于Golang闭包代码解析 - 书中讲解不够清晰求解答的实战教程也可以访问 https://www.itying.com/category-94-b0.html

2 回复
package main

import (
	"fmt"
	"net/http"
)

func testHandlerFunc(w http.ResponseWriter, r *http.Request) {
	fmt.Println("Printing from testHandlerFunc")
	w.Write([]byte("From testHandlerFunc\n"))
}

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

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

		fmt.Println("Executing before request phase")

		testHandlerFunc(w, r)  // 这是在做什么?
		// 这是用当前函数作用域的 http.ResponseWriter 和 http.Request 
		// 调用上面定义的 testHandlerFunc,即此处理器的参数

		handler.ServeHTTP(w, r)

		fmt.Println("Executing after response phase")
	})
}

func mainLogic(w http.ResponseWriter, r *http.Request) {
	fmt.Println("Executing mainLogic")
	w.Write([]byte("OK"))
}

func main() {

	mainLogicHandler := http.HandlerFunc(mainLogic)  // 我不完全理解为什么要把 "mainLogic" 放入 http.HandlerFunc() 类型
	// 这不是类型,而是一个返回 HandlerFunc 的函数调用,它为你基本的接口定义函数
	// 提供了实际成为 HandlerFunc 所需的额外方法,例如 ServeHTTP
	http.Handle("/", middleware(mainLogicHandler))  // 我理解这部分
}

更多关于Golang闭包代码解析 - 书中讲解不够清晰求解答的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


这是一个典型的Go语言中间件模式实现,通过闭包来包装HTTP处理器。让我详细解析代码中的关键部分:

闭包中间件解析

func middleware(handler http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("Executing before request phase")
        
        testHandlerFunc(w, r)  // 这里直接调用testHandlerFunc
        
        handler.ServeHTTP(w, r)  // 执行被包装的处理器
        
        fmt.Println("Executing after response phase")
    })
}

关键点解释:

  1. testHandlerFunc(w, r)的作用

    • 这行代码在中间件中直接调用另一个处理器函数
    • 它会先执行testHandlerFunc的逻辑,然后才执行原始的mainLogic
    • 实际上这会破坏正常的请求处理流程,因为两个处理器都会尝试写入响应
  2. 正确的中间件模式

func properMiddleware(handler http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        fmt.Println("Executing before request phase")
        // 这里应该只做预处理,比如认证、日志等
        // 不应该直接调用其他处理器
        
        handler.ServeHTTP(w, r)  // 继续执行链中的下一个处理器
        
        fmt.Println("Executing after response phase")
    })
}

http.HandlerFunc类型转换解析

mainLogicHandler := http.HandlerFunc(mainLogic)

为什么需要这个转换:

  1. 类型系统要求http.Handle函数需要http.Handler接口类型
  2. 适配器模式http.HandlerFunc是一个函数类型,它实现了http.Handler接口
// 在net/http包中的定义:
type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

type HandlerFunc func(ResponseWriter, *Request)

func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)  // 这里调用原始函数
}

实际执行流程:

  1. 请求到达 / 路径
  2. 调用 middleware(mainLogicHandler)
  3. 中间件闭包执行前置逻辑
  4. 调用 handler.ServeHTTP(w, r)mainLogicHandler.ServeHTTP(w, r)
  5. mainLogicHandler.ServeHTTP 调用 mainLogic(w, r)
  6. 中间件闭包执行后置逻辑

完整的工作示例

func loggingMiddleware(handler http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        fmt.Printf("Started %s %s\n", r.Method, r.URL.Path)
        
        handler.ServeHTTP(w, r)
        
        fmt.Printf("Completed %s in %v\n", r.URL.Path, time.Since(start))
    })
}

func authMiddleware(handler http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("Authorization")
        if token != "valid-token" {
            http.Error(w, "Unauthorized", http.StatusUnauthorized)
            return
        }
        handler.ServeHTTP(w, r)
    })
}

func main() {
    mainHandler := http.HandlerFunc(mainLogic)
    
    // 中间件链:logging -> auth -> mainLogic
    chain := loggingMiddleware(authMiddleware(mainHandler))
    
    http.Handle("/", chain)
    http.ListenAndServe(":8080", nil)
}

这种闭包模式允许你在不修改原始处理器的情况下,为HTTP请求处理添加额外的功能层。

回到顶部