description
elton实例的相关方法说明

Application

New

创建一个elton实例,并初始化相应的http.Server。

Example

  1. package main
  2. import (
  3. "github.com/vicanso/elton"
  4. )
  5. func main() {
  6. e := elton.New()
  7. err := e.ListenAndServe(":3000")
  8. if err != nil {
  9. panic(err)
  10. }
  11. }

NewWithoutServer

创建一个Elton的实例,并未初始化相应的http.Server,主要用于需要自定义http server的场景,如各类超时设置等。

Example

  1. package main
  2. import (
  3. "net/http"
  4. "time"
  5. "github.com/vicanso/elton"
  6. )
  7. func main() {
  8. e := elton.NewWithoutServer()
  9. s := &http.Server{
  10. Handler: e,
  11. ReadTimeout: 5 * time.Second,
  12. WriteTimeout: 10 * time.Second,
  13. }
  14. e.Server = s
  15. err := e.ListenAndServe(":3000")
  16. if err != nil {
  17. panic(err)
  18. }
  19. }

ErrorHandler

自定义的Error处理,若路由处理过程中返回Error,则会触发此调用,若未指定此处理函数,则使用默认的处理,简单的输出err.Error()

注意若在处理过程中返回的Error已被处理(如Error Handler),则并不会触发此出错调用,尽量使用中间件将Error转换为相应的输出(如JSON),而此处理仅用于针对未处理出错响应。

Example

  1. package main
  2. import (
  3. "log"
  4. "net/http"
  5. "github.com/vicanso/elton"
  6. "github.com/vicanso/hes"
  7. )
  8. func main() {
  9. e := elton.New()
  10. e.ErrorHandler = func(c *elton.Context, err error) {
  11. if err != nil {
  12. log.Printf("未处理异常,url:%s, err:%v", c.Request.RequestURI, err)
  13. }
  14. he, ok := err.(*hes.Error)
  15. if ok {
  16. c.Response.WriteHeader(he.StatusCode)
  17. c.Response.Write([]byte(he.Message))
  18. } else {
  19. c.Response.WriteHeader(http.StatusInternalServerError)
  20. c.Response.Write([]byte(err.Error()))
  21. }
  22. }
  23. e.GET("/", func(c *elton.Context) (err error) {
  24. return hes.New("abcd")
  25. })
  26. err := e.ListenAndServe(":3000")
  27. if err != nil {
  28. panic(err)
  29. }
  30. }

NotFoundHandler

未匹配到相应路由时的处理,当无法获取到相应路由时,则会调用此函数(未匹配相应路由时,所有的中间件也不会被调用)。如果有相关统计需要或者自定义的404页面,则可调整此函数,否则可不设置使用默认处理(返回404 Not Found)。

Example

  1. package main
  2. import (
  3. "log"
  4. "net/http"
  5. "github.com/vicanso/elton"
  6. "github.com/vicanso/hes"
  7. )
  8. func main() {
  9. e := elton.New()
  10. e.NotFoundHandler = func(resp http.ResponseWriter, req *http.Request) {
  11. // 可增加统计,方便分析404的处理是被攻击还是接口调用错误
  12. log.Printf("404, url:%s", req.RequestURI)
  13. resp.WriteHeader(http.StatusNotFound)
  14. resp.Write([]byte("Custom not found"))
  15. }
  16. e.GET("/ping", func(c *elton.Context) (err error) {
  17. return hes.New("abcd")
  18. })
  19. err := e.ListenAndServe(":3000")
  20. if err != nil {
  21. panic(err)
  22. }
  23. }

MethodNotAllowedHandler

该HTTP请求方式不允许,路由匹配正确但是method不匹配时,则会调用此函数(此时所有的中间件也不会被调用)。如果有相关统计需要或者自定义的405页面,则可调整此函数,否则可不设置使用默认处理(返回405 Method Not Allowed)。

Example

  1. package main
  2. import (
  3. "log"
  4. "net/http"
  5. "github.com/vicanso/elton"
  6. "github.com/vicanso/hes"
  7. )
  8. func main() {
  9. e := elton.New()
  10. e.MethodNotAllowedHandler = func(resp http.ResponseWriter, req *http.Request) {
  11. // 可增加统计,方便分析405的处理是被攻击还是接口调用错误
  12. log.Printf("405, method: %s, url:%s", req.Method, req.RequestURI)
  13. resp.WriteHeader(http.StatusMethodNotAllowed)
  14. resp.Write([]byte("Custom method not allowed"))
  15. }
  16. e.GET("/ping", func(c *elton.Context) (err error) {
  17. return hes.New("abcd")
  18. })
  19. err := e.ListenAndServe(":3000")
  20. if err != nil {
  21. panic(err)
  22. }
  23. }

GenerateID

ID生成函数,用于每次请求调用时,生成唯一的ID值。

Example

  1. package main
  2. import (
  3. "log"
  4. "math/rand"
  5. "time"
  6. "github.com/oklog/ulid"
  7. "github.com/vicanso/elton"
  8. "github.com/vicanso/elton/middleware"
  9. )
  10. func main() {
  11. e := elton.New()
  12. e.GenerateID = func() string {
  13. t := time.Now()
  14. entropy := rand.New(rand.NewSource(t.UnixNano()))
  15. return ulid.MustNew(ulid.Timestamp(t), entropy).String()
  16. }
  17. e.Use(middleware.NewDefaultResponder())
  18. e.GET("/", func(c *elton.Context) (err error) {
  19. log.Println(c.ID)
  20. c.Body = c.ID
  21. return
  22. })
  23. err := e.ListenAndServe(":3000")
  24. if err != nil {
  25. panic(err)
  26. }
  27. }

EnableTrace

是否启用调用跟踪,设置此参数为true,则会记录每个Handler的调用时长,建议使用时对全局中间件设定名称。

Example

  1. package main
  2. import (
  3. "log"
  4. "github.com/vicanso/elton"
  5. "github.com/vicanso/elton/middleware"
  6. )
  7. func main() {
  8. e := elton.New()
  9. e.EnableTrace = true
  10. e.OnTrace(func(c *elton.Context, traceInfos elton.TraceInfos) {
  11. log.Println(traceInfos[0])
  12. // 设置HTTP响应头:Server-Timing
  13. c.ServerTiming(traceInfos, "elton-")
  14. })
  15. fn := middleware.NewDefaultResponder()
  16. // 自定义该中间件的名称,如果设置为"-",则忽略该中间件
  17. e.UseWithName(fn, "responder")
  18. e.GET("/", func(c *elton.Context) (err error) {
  19. c.Body = "Hello, World!"
  20. return
  21. })
  22. err := e.ListenAndServe(":3000")
  23. if err != nil {
  24. panic(err)
  25. }
  26. }

SignedKeys

用于生成带签名的cookie的密钥,基于keygrip来生成与校验是否合法。使用SignedCookie获取cookie时,会校验cookie的合法性,而AddSignedCookie则会在添加cookie的同时再另外添加相对应的sig cookie。

Example

  1. package main
  2. import (
  3. "bytes"
  4. "net/http"
  5. "github.com/vicanso/elton"
  6. )
  7. func main() {
  8. e := elton.New()
  9. e.SignedKeys = new(elton.RWMutexSignedKeys)
  10. // 密钥,用于生成cookie的签名
  11. e.SignedKeys.SetKeys([]string{
  12. "secret key",
  13. })
  14. e.GET("/", func(c *elton.Context) (err error) {
  15. cookie, _ := c.SignedCookie("jt")
  16. // 如果该cookie不存在
  17. if cookie == nil {
  18. // 设置signed cookie
  19. err = c.AddSignedCookie(&http.Cookie{
  20. Name: "jt",
  21. Value: "abcd",
  22. })
  23. if err != nil {
  24. return
  25. }
  26. }
  27. c.BodyBuffer = bytes.NewBufferString("Hello, World!")
  28. return
  29. })
  30. err := e.ListenAndServe(":3000")
  31. if err != nil {
  32. panic(err)
  33. }
  34. }

ListenAndServe

设定监听地址,并调用http.Server的ListenAndServe提供HTTP服务。

Example

  1. package main
  2. import (
  3. "github.com/vicanso/elton"
  4. )
  5. func main() {
  6. e := elton.New()
  7. err := e.ListenAndServe(":3000")
  8. if err != nil {
  9. panic(err)
  10. }
  11. }

ListenAndServeTLS

设定监听地址,并调用http.Server的ListenAndServeTLS提供HTTPS服务。

Example

  1. package main
  2. import (
  3. "github.com/vicanso/elton"
  4. )
  5. func main() {
  6. // 加密证书相关路径
  7. certFile := "~/cert/cert"
  8. keyFile := "~/cert/key"
  9. e := elton.New()
  10. err := e.ListenAndServeTLS(":3000", certFile, keyFile)
  11. if err != nil {
  12. panic(err)
  13. }
  14. }

Close

关闭服务,调用http.Server的Close方法。

Example

  1. package main
  2. import (
  3. "time"
  4. "github.com/vicanso/elton"
  5. )
  6. func main() {
  7. e := elton.New()
  8. go func() {
  9. time.Sleep(5 * time.Second)
  10. e.Close()
  11. }()
  12. err := e.ListenAndServe(":3000")
  13. if err != nil {
  14. panic(err)
  15. }
  16. }

GracefulClose

优雅的关闭当前服务,首先将实例的状态设置为StatusClosing,此时所有新的请求都将直接出错,在等于指定时间后,则调用http.Server的Close方法。

Example

  1. package main
  2. import (
  3. "time"
  4. "github.com/vicanso/elton"
  5. )
  6. func main() {
  7. e := elton.New()
  8. go func() {
  9. e.GracefulClose(10 * time.Second)
  10. }()
  11. err := e.ListenAndServe(":3000")
  12. if err != nil {
  13. panic(err)
  14. }
  15. }

Handle

添加Handler的处理函数,配置请求的Method与Path,添加相应的处理函数。Elton还支持GET,POST,PUT,PATCH,DELETE,HEAD,TRACE以及OPTIONS的方法,这几个方法与Handle一致,Method则为相对应的处理,以及可使用ALL来指定支持所有的http method。

Example

  1. package main
  2. import (
  3. "github.com/vicanso/elton"
  4. "github.com/vicanso/elton/middleware"
  5. )
  6. func main() {
  7. e := elton.New()
  8. e.Use(middleware.NewDefaultResponder())
  9. noop := func(c *elton.Context) error {
  10. return c.Next()
  11. }
  12. e.Handle("GET", "/", noop, func(c *elton.Context) (err error) {
  13. c.Body = "Hello, World!"
  14. return
  15. })
  16. e.POST("/users/{type}", func(c *elton.Context) (err error) {
  17. c.Body = "OK"
  18. return
  19. })
  20. e.GET("/files/*", func(c *elton.Context) (err error) {
  21. c.Body = "file content"
  22. return
  23. })
  24. err := e.ListenAndServe(":3000")
  25. if err != nil {
  26. panic(err)
  27. }
  28. }

Use/UseWithName

添加全局中间件处理函数,对于所有路由都需要使用到的中间件,则使用此函数添加,若非所有路由都使用到,可以只添加到相应的Group或者就单独添加至Handler。特别需要注意的是,如session之类需要读取数据库的,如非必要,不要使用全局中间件形式。UseWithName在添加中间件时指定其名称,用于在trace时生成统计耗时使用。

Example

  1. package main
  2. import (
  3. "log"
  4. "time"
  5. "github.com/vicanso/elton"
  6. "github.com/vicanso/elton/middleware"
  7. )
  8. func main() {
  9. e := elton.New()
  10. // 记录HTTP请求的时间、响应码
  11. e.Use(func(c *elton.Context) (err error) {
  12. startedAt := time.Now()
  13. req := c.Request
  14. err = c.Next()
  15. log.Printf("%s %s %d use %s", req.Method, req.URL.RequestURI(), c.StatusCode, time.Since(startedAt).String())
  16. return err
  17. })
  18. e.UseWithName(middleware.NewDefaultResponder(), "responder")
  19. e.GET("/", func(c *elton.Context) (err error) {
  20. c.Body = "Hello, World!"
  21. return
  22. })
  23. err := e.ListenAndServe(":3000")
  24. if err != nil {
  25. panic(err)
  26. }
  27. }

Pre

添加全局前置中间件处理函数,对于所有请求都会调用(包括无匹配路由的请求),一般用于前置时对url做调整,如删除前缀等。

Example

  1. package main
  2. import (
  3. "net/http"
  4. "strings"
  5. "github.com/vicanso/elton"
  6. "github.com/vicanso/elton/middleware"
  7. )
  8. func main() {
  9. e := elton.New()
  10. // 如果url以/api开头,则替换
  11. urlPrefix := "/api"
  12. e.Pre(func(req *http.Request) {
  13. path := req.URL.Path
  14. if strings.HasPrefix(path, urlPrefix) {
  15. req.URL.Path = path[len(urlPrefix):]
  16. }
  17. })
  18. e.Use(middleware.NewDefaultResponder())
  19. e.GET("/", func(c *elton.Context) (err error) {
  20. c.Body = "Hello, World!"
  21. return
  22. })
  23. err := e.ListenAndServe(":3000")
  24. if err != nil {
  25. panic(err)
  26. }
  27. }

AddGroup

将group中的所有路由处理添加至Elton,需要注意,在调用AddGroup时则将该分组下的所有路由都添加至实例,因此如果在AddGroup后再调整该group则是无效的。

Example

  1. package main
  2. import (
  3. "github.com/vicanso/elton"
  4. "github.com/vicanso/elton/middleware"
  5. )
  6. func main() {
  7. e := elton.New()
  8. e.Use(middleware.NewDefaultResponder())
  9. userGroup := elton.NewGroup("/users", func(c *elton.Context) error {
  10. return c.Next()
  11. })
  12. userGroup.GET("/me", func(c *elton.Context) error {
  13. c.Body = "nickname"
  14. return nil
  15. })
  16. e.AddGroup(userGroup)
  17. err := e.ListenAndServe(":3000")
  18. if err != nil {
  19. panic(err)
  20. }
  21. }

OnError

添加Error的监听函数,如果当任一Handler的处理返回Error,并且其它的Handler并未将此Error处理(建议使用专门的中间件处理出错),则会触发error事件,建议使用此事件来监控程序未处理异常。

Example

  1. package main
  2. import (
  3. "errors"
  4. "log"
  5. "github.com/vicanso/elton"
  6. "github.com/vicanso/elton/middleware"
  7. )
  8. func main() {
  9. e := elton.New()
  10. e.OnError(func(c *elton.Context, err error) {
  11. // 发送邮件告警等
  12. log.Println("error: " + err.Error())
  13. })
  14. e.Use(middleware.NewDefaultResponder())
  15. e.GET("/", func(c *elton.Context) (err error) {
  16. c.Body = "Hello, World!"
  17. return
  18. })
  19. // 由于未设置公共的出错处理中间件,此error会触发事件
  20. // 实际使用中,需要添加公共的error handler来处理,error事件只用于监控异常的出错
  21. e.GET("/error", func(c *elton.Context) (err error) {
  22. return errors.New("abcd")
  23. })
  24. err := e.ListenAndServe(":3000")
  25. if err != nil {
  26. panic(err)
  27. }
  28. }