Golang Http Handlers as Middleware

From: http://capotej.com/

转者按:本文介绍了如何hook一个http的处理函数,从而加入自定义的内容。


Most modern web stacks allow the “filtering” of requests via stackable/composable middleware, allowing you to cleanly separate cross-cutting concerns from your web application. This weekend I needed to hook into go’s http.FileServer and was pleasantly surprised how easy it was to do.

Let’s start with a basic file server for /tmp:

main.go
1
2
3
func main() {
    http.ListenAndServe(":8080", http.FileServer(http.Dir("/tmp")))
}

This starts up a local file server at :8080. How can we hook into this so we can run some code before file requests are served? Let’s look at the method signature for http.ListenAndServe:

1
func ListenAndServe(addr string, handler Handler) error

So it looks like http.FileServer returns a Handler that knows how to serve files given a root directory. Now let’s look at the Handler interface:

1
2
3
type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

Because of go’s granular interfaces, any object can be a Handler so long as it implements ServeHTTP. It seems all we need to do is construct our own Handler that wraps http.FileServer’s handler. There’s a built in helper for turning ordinary functions into handlers called http.HandlerFunc:

1
type HandlerFunc func(ResponseWriter, *Request)

Then we just wrap http.FileServer like so:

main.go
1
2
3
4
5
6
7
8
9
10
11
12
func OurLoggingHandler(h http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Println(*r.URL)
    h.ServeHTTP(w, r)
  })
}

func main() {
    fileHandler := http.FileServer(http.Dir("/tmp"))
    wrappedHandler := OurLoggingHandler(fileHandler)
    http.ListenAndServe(":8080", wrappedHandler)
}

Go has a bunch of other builtin handlers like TimeoutHandler and RedirectHandler that can be mixed and matched the same way.


另一种方式参考https://github.com/philsong/golang_samples/blob/master/src/emvdecoder/emvdecoder.go


type TraceHandler struct {
        h http.Handler
        n int
}

func (r *TraceHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
        r.n++
        fmt.Printf("counter = %d\n", r.n) //why counter always zero
        fmt.Println("get", req.URL.Path, " from ", req.RemoteAddr)
        r.h.ServeHTTP(w, req)
}

func main() {
        port := "9090" //Default port
        if len(os.Args) > 1 {
                port = strings.Join(os.Args[1:2], "")
        }
        h := http.StripPrefix("/icclogs/", http.FileServer(http.Dir("./logs/")))
        http.Handle("/icclogs/", &TraceHandler{h: h, n: 0})

        println("Listening on port ", port, "...")
        err := http.ListenAndServe(":"+port, nil) //设置监听的端口

        if err != nil {
                log.Fatal("ListenAndServe: ", err)
        }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]中的代码是一个用于限制读取数据大小的函数。它首先读取指定大小的数据,然后再次读取一个字节,如果返回的错误是EOF,则表示数据已经读取完毕。如果返回的错误不是EOF,则表示数据超过了指定的大小。\[1\] 引用\[2\]中的代码是一个使用golang.org/x/net/websocket包实现的简单的WebSocket服务器。它通过接收客户端发送的消息,并将接收到的消息发送回客户端。\[2\] 引用\[3\]中的代码是一个使用golang.org/x/net/websocket包的前端代码。它在接收到消息时会报错。\[3\] 根据提供的引用内容,无法确定具体的问题是什么。请提供更具体的问题描述,以便我能够给出更准确的答案。 #### 引用[.reference_title] - *1* [golang http 1.1 max body实现](https://blog.csdn.net/u014763610/article/details/122852010)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Go websocket EOF bug](https://blog.csdn.net/happy_teemo/article/details/114317294)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值