golang实现HTTP中间件的惯用方式插件库negroni的使用

Golang实现HTTP中间件的惯用方式插件库Negroni的使用

Negroni是Go语言中一种惯用的Web中间件方法。它小巧、非侵入式,并鼓励使用net/http Handlers。

快速开始

安装好Go并设置好GOPATH后,创建第一个.go文件,例如server.go

package main

import (
  "fmt"
  "net/http"

  "github.com/urfave/negroni/v3"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  n := negroni.Classic() // 包含一些默认中间件
  n.UseHandler(mux)

  http.ListenAndServe(":3000", n)
}

安装Negroni包(注意:需要Go 1.1或更高版本):

go get github.com/urfave/negroni/v3

然后运行服务器:

go run server.go

现在你将在localhost:3000上运行一个Go net/http Web服务器。

Negroni是一个框架吗?

Negroni不是一个框架。它是一个专注于中间件的库,设计为直接与net/http一起工作。

路由

Negroni是"自带路由器"(BYOR)。Go社区已经有许多优秀的HTTP路由器可用,Negroni通过完全支持net/http与它们良好配合。例如,与Gorilla Mux集成如下:

router := mux.NewRouter()
router.HandleFunc("/", HomeHandler)

n := negroni.New(Middleware1, Middleware2)
// 或者使用Use()函数添加中间件
n.Use(Middleware3)
// 路由器最后添加
n.UseHandler(router)

http.ListenAndServe(":3001", n)

negroni.Classic()

negroni.Classic()提供了一些对大多数应用有用的默认中间件:

  1. negroni.Recovery - 恐慌恢复中间件
  2. negroni.Logger - 请求/响应日志中间件
  3. negroni.Static - 在"public"目录下提供静态文件服务

这使得可以轻松地开始使用Negroni的一些有用功能。

处理器(Handlers)

Negroni提供了双向中间件流。这是通过negroni.Handler接口实现的:

type Handler interface {
  ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc)
}

如果中间件尚未写入ResponseWriter,它应该调用链中的下一个http.HandlerFunc来让位给下一个中间件处理器。这可以用来做很多好事:

func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
  // 之前做一些事情
  next(rw, r)
  // 之后做一些事情
}

你可以使用Use函数将其映射到处理器链:

n := negroni.New()
n.Use(negroni.HandlerFunc(MyMiddleware))

你也可以映射普通的http.Handler

n := negroni.New()

mux := http.NewServeMux()
// 映射你的路由

n.UseHandler(mux)

http.ListenAndServe(":3000", n)

路由特定中间件

如果你有一组需要执行特定中间件的路由,你可以简单地创建一个新的Negroni实例并将其用作路由处理器。

router := mux.NewRouter()
adminRoutes := mux.NewRouter()
// 在这里添加管理路由

// 为管理中间件创建一个新的negroni
router.PathPrefix("/admin").Handler(negroni.New(
  Middleware1,
  Middleware2,
  negroni.Wrap(adminRoutes),
))

捆绑的中间件

静态文件(Static)

这个中间件将提供文件系统上的文件。如果文件不存在,它将把请求代理给下一个中间件。

package main

import (
  "fmt"
  "net/http"

  "github.com/urfave/negroni/v3"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  n := negroni.New()
  n.Use(negroni.NewStatic(http.Dir("/tmp")))
  n.UseHandler(mux)

  http.ListenAndServe(":3002", n)
}

恢复(Recovery)

这个中间件捕获panic并以500状态码响应。

package main

import (
  "net/http"

  "github.com/urfave/negroni/v3"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    panic("oh no")
  })

  n := negroni.New()
  n.Use(negroni.NewRecovery())
  n.UseHandler(mux)

  http.ListenAndServe(":3003", n)
}

日志(Logger)

这个中间件记录每个传入的请求和响应。

package main

import (
  "fmt"
  "net/http"

  "github.com/urfave/negroni/v3"
)

func main() {
  mux := http.NewServeMux()
  mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
    fmt.Fprintf(w, "Welcome to the home page!")
  })

  n := negroni.New()
  n.Use(negroni.NewLogger())
  n.UseHandler(mux)

  http.ListenAndServe(":3004", n)
}

第三方中间件

有许多与Negroni兼容的第三方中间件可用,包括:

  • 认证中间件 (authz, oauth2, JWT等)
  • 监控中间件 (New Relic, Prometheus等)
  • 安全中间件 (CORS, CSP等)
  • 会话管理
  • 数据绑定
  • 和其他许多

示例项目

  • mooseware - 编写Negroni中间件处理程序的骨架
  • Go-Skeleton - 基于Go/Negroni的Web项目有效骨架结构

Negroni由Code Gangsta精心设计。


更多关于golang实现HTTP中间件的惯用方式插件库negroni的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现HTTP中间件的惯用方式插件库negroni的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang HTTP中间件实现及Negroni使用指南

在Go语言中,HTTP中间件是一种非常强大且常用的模式,它允许我们在处理HTTP请求和响应的过程中插入自定义逻辑。下面我将介绍Go中实现HTTP中间件的几种方式,并重点介绍Negroni这个流行的中间件库。

1. 原生Go实现HTTP中间件

基本中间件模式

func loggingMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        
        // 在调用处理程序前执行的操作
        log.Printf("Started %s %s", r.Method, r.URL.Path)
        
        // 调用下一个处理程序
        next.ServeHTTP(w, r)
        
        // 在处理程序完成后执行的操作
        log.Printf("Completed %s in %v", r.URL.Path, time.Since(start))
    })
}

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello, World!"))
    })
    
    // 使用中间件包装处理器
    wrappedMux := loggingMiddleware(mux)
    
    http.ListenAndServe(":8080", wrappedMux)
}

多中间件链式调用

func middlewareOne(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Println("Executing middlewareOne")
        next.ServeHTTP(w, r)
        log.Println("Executing middlewareOne again")
    })
}

func middlewareTwo(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Println("Executing middlewareTwo")
        if r.URL.Path == "/forbidden" {
            w.WriteHeader(http.StatusForbidden)
            return
        }
        next.ServeHTTP(w, r)
        log.Println("Executing middlewareTwo again")
    })
}

func main() {
    finalHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        log.Println("Executing finalHandler")
        w.Write([]byte("OK"))
    })
    
    // 构建中间件链
    chain := middlewareOne(middlewareTwo(finalHandler))
    
    http.ListenAndServe(":8080", chain)
}

2. 使用Negroni中间件库

Negroni是一个专注于HTTP中间件的微型库,它提供了更简洁的方式来组织和组合中间件。

安装Negroni

go get github.com/urfave/negroni

基本使用示例

package main

import (
    "fmt"
    "net/http"
    "time"
    
    "github.com/urfave/negroni"
)

func main() {
    // 创建新的Negroni实例
    n := negroni.New()
    
    // 添加内置中间件
    n.Use(negroni.NewRecovery())  // 崩溃恢复
    n.Use(negroni.NewLogger())    // 请求日志
    
    // 添加自定义中间件
    n.Use(negroni.HandlerFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
        fmt.Println("Before request")
        start := time.Now()
        
        next(w, r)
        
        fmt.Printf("After request (took %v)\n", time.Since(start))
    }))
    
    // 设置路由处理器
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusOK)
        fmt.Fprintf(w, "Welcome to the home page!")
    })
    
    // 将路由器作为最后一个处理器
    n.UseHandler(mux)
    
    // 启动服务器
    http.ListenAndServe(":3000", n)
}

Negroni中间件类型

Negroni支持三种形式的中间件:

  1. negroni.Handler 接口实现
  2. negroni.HandlerFunc 函数适配器
  3. http.Handler 接口实现
// 1. 实现negroni.Handler接口
type CustomMiddleware struct{}

func (m *CustomMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
    fmt.Println("CustomMiddleware before")
    next(w, r)
    fmt.Println("CustomMiddleware after")
}

// 2. 使用negroni.HandlerFunc
middlewareFunc := negroni.HandlerFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
    fmt.Println("HandlerFunc before")
    next(w, r)
    fmt.Println("HandlerFunc after")
})

// 3. 使用http.Handler
httpMiddleware := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    fmt.Println("http.Handler middleware")
})

常用Negroni中间件

Negroni生态系统中有许多有用的中间件:

n := negroni.New()

// 静态文件服务
n.Use(negroni.NewStatic(http.Dir("public")))

// 添加多个中间件
n.Use(
    negroni.NewRecovery(),
    negroni.NewLogger(),
    &CustomMiddleware{},
    middlewareFunc,
    negroni.Wrap(httpMiddleware),
)

路由集成

Negroni常与Gorilla Mux或httprouter等路由器配合使用:

import (
    "github.com/gorilla/mux"
    "github.com/urfave/negroni"
)

func main() {
    router := mux.NewRouter()
    router.HandleFunc("/", homeHandler)
    router.HandleFunc("/products", productsHandler)
    
    n := negroni.New(
        negroni.NewRecovery(),
        negroni.NewLogger(),
    )
    
    n.UseHandler(router)
    http.ListenAndServe(":3000", n)
}

3. 创建可配置的中间件

func NewAuthMiddleware(realm string) negroni.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
        user, pass, ok := r.BasicAuth()
        
        if !ok || user != "admin" || pass != "secret" {
            w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
            w.WriteHeader(401)
            w.Write([]byte("Unauthorized\n"))
            return
        }
        
        next(w, r)
    }
}

func main() {
    n := negroni.New()
    n.Use(NewAuthMiddleware("Restricted Area"))
    
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Welcome to the protected area!"))
    })
    
    n.UseHandler(mux)
    http.ListenAndServe(":3000", n)
}

总结

Negroni提供了一种简洁、灵活的方式来组织HTTP中间件,它的设计哲学是"做一件事并做好"。相比原生实现,Negroni提供了:

  1. 更清晰的中间件链式调用语法
  2. 内置常用中间件(日志、恢复等)
  3. 更好的与各种路由器集成
  4. 更直观的中间件编写方式

对于大多数项目,使用Negroni可以显著简化中间件的管理和维护工作,同时保持代码的清晰和可维护性。

回到顶部