Skip to content

Latest commit

 

History

History
488 lines (362 loc) · 15.6 KB

README_zh_tw.md

File metadata and controls

488 lines (362 loc) · 15.6 KB

Negroni(尼格龍尼)

GoDoc Build Status codebeat codecov

注意: 本函式庫原來自於 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嗎?

尼格龍尼不是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.Classic() 提供一些好用的預設中介器:

尼格龍尼的這些功能讓你開發變得很簡單.

處理器(Handlers)

尼格龍尼提供一個雙向中介器的機制, 介面為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, 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

第三方中介器

以下清單是目前可用於尼格龍尼的中介器. 如果你自己手癢做了一個, 請別吝嗇自己把連結貼在下面吧:

中介器 作者 說明
authz Yang Luo 一款使用Casbin的權限管理中介器可支援ACL, RBAC, ABAC
binding Matt Holt 把HTTP請求的資料榜定到structs
cloudwatch Colin Steele AWS CloudWatch 矩陣的中介器
cors Olivier Poitrey 支援Cross Origin Resource Sharing(CORS)
csp Awake Networks 支援Content Security Policy(CSP)
delay Jeff Martinez 為endpoints增加延遲時間. 在測試嚴重網路延遲的效應時好用
New Relic Go Agent Yadvendar Champawat 官網 New Relic Go Agent (目前正在測試階段)
gorelic Jingwen Owen Ou New Relic agent for Go runtime
Graceful Tyler Bunnell 優雅地關閉HTTP
gzip phyber GZIP資源壓縮
JWT Middleware Auth0 Middleware 檢查JWT在Authorization header on incoming requests and decodes it
logrus Dan Buch 基於Logrus的紀錄器
oauth2 David Bochenski oAuth2中介器
onthefly Alexander Rødseth 一秒產生TinySVG, HTML, CSS
permissions2 Alexander Rødseth Cookies與使用者權限配套
prometheus Rene Zbinden 簡易建立矩陣端點給prometheus建構工具
render Cory Jacobsen JSON, XML, HTML樣板的渲染
RestGate Prasanga Siripala REST API端點安全認證
secure Cory Jacobsen 簡易安全中介器
sessions David Bochenski Session 管理
stats Florent Messa 儲存關於網頁應用的資訊(回應時間之類)
VanGoH Taylor Wrobel 可設定的AWS風格 HMAC認證中介器
xrequestid Andrea Franz 在每個request指定一個隨機X-Request-Id header的中介器
mgo session Joel James 處理在每個請求建立與關閉mgo sessions
digits Bilal Amarni 處理Twitter Digits的認證
stats Chirag Gupta 終端用的管理QPS與延遲狀態的中介器非同步地將狀態刷入InfluxDB
Chaos Marc Falzon 以開發的方式在應用程式中插入無序行為的中介器

應用範例

Alexander Rødseth所建 mooseware用來寫尼格龍尼中介處理器的骨架 Go-Skeleton有效的網頁GO尼格龍尼骨架

即時編譯

ginfresh兩個尼格龍尼即時重載的應用.

Go & 尼格龍尼初學者必讀

關於

尼格龍尼正是Code Gangsta的執著設計.

譯者: Festum Qin ([email protected])