注意: 本函式庫原來自於
github.com/codegangsta/negroni
-- Github會自動將連線轉到本連結, 但我們建議你更新一下參照.
尼格龍尼是一款web中介器. 道地的Go寫法、精簡、非侵入、鼓勵用net/http
處理器.
如果你喜歡Martini, 但覺得這其中包太多神奇的功能, 那麼尼格龍尼會是你的最佳選擇.
其他語言:
安裝完Go且設好GOPATH, 建立你的第一個.go
檔. 可以命名為server.go
.
package main
import (
"fmt"
"net/http"
"github.com/urfave/negroni"
)
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)
}
安裝尼格龍尼套件 (最低需求為go 1.1或更高版本):
go get github.com/urfave/negroni
執行伺服器:
go run server.go
你現在起了一個Go的net/http網頁伺服器在localhost:3000
.
如果negroni
在Debian環境下是個套件, 可直接
執行apt install golang-github-urfave-negroni-dev
安裝(這在sid
倉庫中).
尼格龍尼不是framework, 是個設計用來直接使用net/http的library.
尼格龍尼是BYOR (Bring your own Router, 帶給你自訂路由). 在Go社群已經有大量可用的http路由器, 尼格龍尼試著做好完全支援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.Recovery
- Panic 還原中介器negroni.Logging
- Request/Response 紀錄中介器negroni.Static
- 在"public"目錄下的靜態檔案服務
尼格龍尼的這些功能讓你開發變得很簡單.
尼格龍尼提供一個雙向中介器的機制, 介面為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()
// map your routes
n.UseHandler(mux)
http.ListenAndServe(":3000", n)
尼格龍尼有一個很好用的函數Run
, Run
接收addr字串辨識http.ListenAndServe.
package main
import (
"github.com/urfave/negroni"
)
func main() {
n := negroni.Classic()
n.Run(":8080")
}
未提供路徑情況下會使用系統環境變數PORT
, 若未定義該系統環境變數則會用預設路徑, 請見Run細看說明.
一般來說, 你會希望使用 net/http
方法, 並且將尼格龍尼當作處理器傳入, 這相對起來彈性比較大, 例如:
package main
import (
"fmt"
"log"
"net/http"
"time"
"github.com/urfave/negroni"
)
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)
s := &http.Server{
Addr: ":8080",
Handler: n,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
log.Fatal(s.ListenAndServe())
}
如果你有一群路由需要執行特別的中介器, 你可以簡單的建立一個新的尼格龍尼實體當作路由處理器.
router := mux.NewRouter()
adminRoutes := mux.NewRouter()
// 在這裡新增管理用的路由
// 為管理中介器建立一個新的尼格龍尼
router.Handle("/admin", negroni.New(
Middleware1,
Middleware2,
negroni.Wrap(adminRoutes),
))
如果你使用 Gorilla Mux, 下方是一個使用 subrounter 的例子:
router := mux.NewRouter()
subRouter := mux.NewRouter().PathPrefix("/subpath").Subrouter().StrictSlash(true)
subRouter.HandleFunc("/", someSubpathHandler) // "/subpath/"
subRouter.HandleFunc("/:id", someSubpathHandler) // "/subpath/:id"
// "/subpath" 是用來保證subRouter與主要路由連結的必要參數
router.PathPrefix("/subpath").Handler(negroni.New(
Middleware1,
Middleware2,
negroni.Wrap(subRouter),
))
With()
可被用來降低在跨路由分享時多餘的中介器.
router := mux.NewRouter()
apiRoutes := mux.NewRouter()
// 在此新增API路由
webRoutes := mux.NewRouter()
// 在此新增Web路由
// 建立通用中介器來跨路由分享
common := negroni.New(
Middleware1,
Middleware2,
)
// 為API中介器建立新的negroni
// 使用通用中介器作底
router.PathPrefix("/api").Handler(common.With(
APIMiddleware1,
negroni.Wrap(apiRoutes),
))
// 為Web中介器建立新的negroni
// 使用通用中介器作底
router.PathPrefix("/web").Handler(common.With(
WebMiddleware1,
negroni.Wrap(webRoutes),
))
本中介器會在檔案系統上服務檔案. 若檔案不存在, 會將流量導(proxy)到下個中介器.
如果你想要返回404 File Not Found
給檔案不存在的請求, 請使用http.FileServer
作為處理器.
範例:
package main
import (
"fmt"
"net/http"
"github.com/urfave/negroni"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Welcome to the home page!")
})
// http.FileServer的使用範例, 若你預期要"像伺服器"而非"中介器"的行為
// mux.Handle("/public", http.FileServer(http.Dir("/home/public")))
n := negroni.New()
n.Use(negroni.NewStatic(http.Dir("/tmp")))
n.UseHandler(mux)
http.ListenAndServe(":3002", n)
}
從/tmp
目錄開始服務檔案 但如果請求的檔案在檔案系統中不符合, 代理會
呼叫下個處理器.
本中介器接收panic
跟錯誤代碼500
的回應. 如果其他任何中介器寫了回應
的HTTP代碼或內容的話, 中介器會無法順利地傳送500給用戶端, 因為用戶端
已經收到HTTP的回應代碼. 另外, 可以掛載PanicHandlerFunc
來回報500
的錯誤到錯誤回報系統, 如: Sentry或Airbrake.
範例:
package main
import (
"net/http"
"github.com/urfave/negroni"
)
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)
}
將回傳500 Internal Server Error
到每個結果. 也會把結果紀錄到堆疊追蹤,
PrintStack
設成true
(預設值)的話也會印到註冊者.
加錯誤處理器的範例:
package main
import (
"net/http"
"github.com/urfave/negroni"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
panic("oh no")
})
n := negroni.New()
recovery := negroni.NewRecovery()
recovery.PanicHandlerFunc = reportToSentry
n.Use(recovery)
n.UseHandler(mux)
http.ListenAndServe(":3003", n)
}
func reportToSentry(info *negroni.PanicInformation) {
// 在這寫些程式回報錯誤給Sentry
}
中介器在預設會簡易的輸出資訊到STDOUT. 你可以使用SetFormatter()
函式客製化輸出的程序.
你也可以使用HTMLPanicFormatter
在錯誤時顯示格式化的HTML.
package main
import (
"net/http"
"github.com/urfave/negroni"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
panic("oh no")
})
n := negroni.New()
recovery := negroni.NewRecovery()
recovery.Formatter = &negroni.HTMLPanicFormatter{}
n.Use(recovery)
n.UseHandler(mux)
http.ListenAndServe(":3003", n)
}
本中介器紀錄各個進入的請求與回應.
範例:
package main
import (
"fmt"
"net/http"
"github.com/urfave/negroni"
)
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] 2017-10-04T14:56:25+02:00 | 200 | 378µs | localhost:3004 | GET /
你也可以用SetFormat
函式來 設定自己的紀錄格式. 格式樣本字串與欄位如LoggerEntry
結構中所述. 例:
l.SetFormat("[{{.Status}} {{.Duration}}] - {{.Request.UserAgent}}")
會顯示像是 - [200 18.263µs] - Go-User-Agent/1.1
以下清單是目前可用於尼格龍尼的中介器. 如果你自己手癢做了一個, 請別吝嗇自己把連結貼在下面吧:
Alexander Rødseth所建 mooseware用來寫尼格龍尼中介處理器的骨架 Go-Skeleton有效的網頁GO尼格龍尼骨架
尼格龍尼正是Code Gangsta的執著設計.
譯者: Festum Qin (Festum@G.PL)