r.GET(“/benchmark”, before, main,after)

使用中间件

  1. func main() {
  2. // 创建一个默认的没有任何中间件的路由
  3. r := gin.New()
  4. // 全局中间件
  5. // Logger 中间件将写日志到 gin.DefaultWriter ,即使你设置 GIN_MODE=release 。
  6. // 默认 gin.DefaultWriter = os.Stdout
  7. r.Use(gin.Logger())
  8. // Recovery 中间件从任何 panic 恢复,如果出现 panic,它会写一个 500 错误。
  9. r.Use(gin.Recovery())
  10. // 每个路由的中间件, 你能添加任意数量的中间件
  11. r.GET("/benchmark", MyBenchLogger(), benchEndpoint)
  12. // 授权组
  13. // authorized := r.Group("/", AuthRequired())
  14. // 也可以这样:
  15. authorized := r.Group("/")
  16. // 每个组的中间件! 在这个实例中,我们只需要在 "authorized" 组中
  17. // 使用自定义创建的 AuthRequired() 中间件
  18. authorized.Use(AuthRequired())
  19. {
  20. authorized.POST("/login", loginEndpoint)
  21. authorized.POST("/submit", submitEndpoint)
  22. authorized.POST("/read", readEndpoint)
  23. // nested group
  24. testing := authorized.Group("testing")
  25. testing.GET("/analytics", analyticsEndpoint)
  26. }
  27. // 监听并服务于 0.0.0.0:8080
  28. r.Run(":8080")
  29. }

自定义中间件

  1. func Logger() gin.HandlerFunc {
  2. return func(c *gin.Context) {
  3. t := time.Now()
  4. // 设置简单的变量
  5. c.Set("example", "12345")
  6. // 在请求之前
  7. c.Next()
  8. // 在请求之后
  9. latency := time.Since(t)
  10. log.Print(latency)
  11. // 记录我们的访问状态
  12. status := c.Writer.Status()
  13. log.Println(status)
  14. }
  15. }
  16. func main() {
  17. r := gin.New()
  18. r.Use(Logger())
  19. r.GET("/test", func(c *gin.Context) {
  20. example := c.MustGet("example").(string)
  21. // 它将打印: "12345"
  22. log.Println(example)
  23. })
  24. // 监听并服务于 0.0.0.0:8080
  25. r.Run(":8080")
  26. }

在中间件中使用协程

在一个中间件或处理器中启动一个新的协成时,你 不应该 使用它里面的原始的 context ,只能去使用它的只读副本。

  1. func main() {
  2. r := gin.Default()
  3. r.GET("/long_async", func(c *gin.Context) {
  4. // 创建在协成中使用的副本
  5. cCp := c.Copy()
  6. go func() {
  7. // 使用 time.Sleep() 休眠 5 秒,模拟一个用时长的任务。
  8. time.Sleep(5 * time.Second)
  9. // 注意,你使用的是复制的 context "cCp" ,重要
  10. log.Println("Done! in path " + cCp.Request.URL.Path)
  11. }()
  12. })
  13. r.GET("/long_sync", func(c *gin.Context) {
  14. // 使用 time.Sleep() 休眠 5 秒,模拟一个用时长的任务。
  15. time.Sleep(5 * time.Second)
  16. // 因为我们没有使用协成,我们不需要复制 context
  17. log.Println("Done! in path " + c.Request.URL.Path)
  18. })
  19. // 监听并服务于 0.0.0.0:8080
  20. r.Run(":8080")
  21. }

使用 BasicAuth () 中间件

  1. // 模拟一些私有的数据
  2. var secrets = gin.H{
  3. "foo": gin.H{"email": "foo@bar.com", "phone": "123433"},
  4. "austin": gin.H{"email": "austin@example.com", "phone": "666"},
  5. "lena": gin.H{"email": "lena@guapa.com", "phone": "523443"},
  6. }
  7. func main() {
  8. r := gin.Default()
  9. // 在组中使用 gin.BasicAuth() 中间件
  10. // gin.Accounts 是 map[string]string 的快捷方式
  11. authorized := r.Group("/admin", gin.BasicAuth(gin.Accounts{
  12. "foo": "bar",
  13. "austin": "1234",
  14. "lena": "hello2",
  15. "manu": "4321",
  16. }))
  17. // /admin/secrets 结尾
  18. // 点击 "localhost:8080/admin/secrets
  19. authorized.GET("/secrets", func(c *gin.Context) {
  20. // 获取 user, 它是由 BasicAuth 中间件设置的
  21. user := c.MustGet(gin.AuthUserKey).(string)
  22. if secret, ok := secrets[user]; ok {
  23. c.JSON(http.StatusOK, gin.H{"user": user, "secret": secret})
  24. } else {
  25. c.JSON(http.StatusOK, gin.H{"user": user, "secret": "NO SECRET :("})
  26. }
  27. })
  28. // 监听并服务于 0.0.0.0:8080
  29. r.Run(":8080")
  30. }

如何写入日志文件

  1. func main() {
  2. // 禁用控制台颜色,当你将日志写入到文件的时候,你不需要控制台颜色。
  3. gin.DisableConsoleColor()
  4. // 写入日志的文件
  5. f, _ := os.Create("gin.log")
  6. gin.DefaultWriter = io.MultiWriter(f)
  7. // 如果你需要同时写入日志文件和控制台上显示,使用下面代码
  8. // gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
  9. router := gin.Default()
  10. router.GET("/ping", func(c *gin.Context) {
  11. c.String(200, "pong")
  12. })
  13. router.Run(":8080")
  14. }

中间键扩展:不拦截自定请求

  1. package middle
  2. import (
  3. "github.com/gin-gonic/gin"
  4. "strings"
  5. )
  6. type SkipFunc func (c *gin.Context) bool
  7. //注意 传过来的path,前面加/
  8. func AllowPathSkip(path ...string) SkipFunc {
  9. return func(c *gin.Context) bool {
  10. thisPath := c.Request.URL.Path
  11. for _,v := range path{
  12. if len(path) >0 || strings.HasPrefix(thisPath,v){
  13. return true
  14. }
  15. }
  16. return false
  17. }
  18. }
  19. func MyMiddle(Skip SkipFunc) gin.HandlerFunc{
  20. return func(context *gin.Context) {
  21. if Skip(context){
  22. context.Next()
  23. return
  24. }
  25. // 下面走正常的中间件逻辑
  26. }
  27. }

优化,每次循环肯定会慢,关键点在于使用map来存住不走该中间键的path

  1. package middle
  2. import (
  3. "github.com/gin-gonic/gin"
  4. )
  5. type SkipFunc func (c *gin.Context) bool
  6. //注意 传过来的path,前面加/
  7. func AllowPathSkip(path ...string) SkipFunc {
  8. var skip map[string]struct{}
  9. if length := len(path); length > 0 {
  10. skip = make(map[string]struct{}, length)
  11. for _,v := range path{
  12. skip[v] = struct{}{}
  13. }
  14. }
  15. return func(c *gin.Context) bool {
  16. if _,ok := skip[c.Request.URL.Path];ok{
  17. return true
  18. }
  19. return false
  20. }
  21. }
  22. func MyMiddle(Skip SkipFunc) gin.HandlerFunc{
  23. return func(context *gin.Context) {
  24. if Skip(context){ // 该请求是否需要跳过
  25. context.Next()
  26. return
  27. }
  28. // 下面走正常的中间件逻辑
  29. }
  30. }

跨域

  1. // 处理跨域请求,支持options访问
  2. func Cors() gin.HandlerFunc {
  3. return func(c *gin.Context) {
  4. method := c.Request.Method
  5. c.Header("Access-Control-Allow-Origin", "*") //必选项
  6. //动态允许Allow-Origin,解决"*"不能与Access-Control-Allow-Credentials为true共存的问题
  7. //ctx.Header("Access-Control-Allow-Origin",ctx.GetHeader("Origin"))
  8. //拿到跨域请求中Header的Token字段,不能用"*"
  9. c.Header("Access-Control-Allow-Headers", "Token,SessionId,Content-Type")
  10. c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS,PUT,DELETE")
  11. c.Header("Access-Control-Allow-Credentials", "true")
  12. // 能够让客户端的js读取到Header
  13. c.Header("Access-Control-Expose-Headers", "X-Powered-By,xxx")
  14. // 表明在xxx秒内,不需要再发送预检验请求,可以缓存该结果
  15. c.Header("Access-Control-Max-Age", "3600")
  16. //如果method是OPTIONS,直接返回成功
  17. //有的模板是要请求两次的
  18. if method == "OPTIONS" {
  19. ctx.AbortWithStatusJSON(http.StatusOK, "Options Request!")
  20. retrun
  21. }
  22. // 处理请求
  23. c.Next()
  24. }
  25. }