Skip to content

Commit

Permalink
feat: add middleware function
Browse files Browse the repository at this point in the history
Signed-off-by: daz-3ux <[email protected]>
  • Loading branch information
Daz-3ux committed Sep 15, 2023
1 parent 59955a9 commit 942f331
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 0 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.21.0

require (
github.com/gin-gonic/gin v1.9.1
github.com/google/uuid v1.1.2
github.com/gosuri/uitable v0.0.4
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
Expand Down
7 changes: 7 additions & 0 deletions internal/dazBlog/dazBlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"errors"
"fmt"
"github.com/Daz-3ux/dBlog/internal/pkg/log"
mw "github.com/Daz-3ux/dBlog/internal/pkg/middleware"
"github.com/Daz-3ux/dBlog/pkg/version/verflag"
"github.com/gin-gonic/gin"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -83,6 +84,11 @@ func run() error {
// create Gin engine
g := gin.New()

// gin.Recovery() middleware is used to capture any panics and recover from them
mws := []gin.HandlerFunc{gin.Recovery(), mw.NoCache, mw.Cors, mw.Secure, mw.RequestID()}

g.Use(mws...)

// register 404 handler
g.LoadHTMLGlob("internal/resource/*.html")
g.NoRoute(func(c *gin.Context) {
Expand All @@ -92,6 +98,7 @@ func run() error {

// register /healthz handler
g.GET("/healthz", func(c *gin.Context) {
log.C(c).Infow("Healthz function called")
c.JSON(http.StatusOK, gin.H{"status": "OK"})
})

Expand Down
5 changes: 5 additions & 0 deletions internal/pkg/known/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## known

- 放置需要共享的 key
- X-Request-ID 会同时被 `日志` 以及 `gin.Context` 需要
- 所以将 key 的名字保存在共享包 `known` 中, 便于使用
11 changes: 11 additions & 0 deletions internal/pkg/known/known.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2023 daz-3ux(杨鹏达) <[email protected]>. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. The original repo for
// this file is https://github.com/Daz-3ux/dBlog.

package known

const (
// XRequestIDKey is used to define the key in the Gin context representing the request UUID.
XRequestIDKey = "X-Request-Id"
)
26 changes: 26 additions & 0 deletions internal/pkg/log/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
package log

import (
"context"
"github.com/Daz-3ux/dBlog/internal/pkg/known"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"

Expand Down Expand Up @@ -171,3 +173,27 @@ func Fatalw(msg string, keysAndValues ...interface{}) {
func (l *zapLogger) Fatalw(msg string, keysAndValues ...interface{}) {
l.z.Sugar().Fatalw(msg, keysAndValues...)
}

// C extracts relevant key-value pairs from the incoming context
// and adds them to the structured logs of the zap.Logger.
func C(ctx context.Context) *zapLogger {
return std.C(ctx)
}

func (l *zapLogger) C(ctx context.Context) *zapLogger {
lc := l.clone()

if requestID := ctx.Value(known.XRequestIDKey); requestID != nil {
lc.z = lc.z.With(zap.Any(known.XRequestIDKey, requestID))
}

return lc
}

// clone deep copy the zapLogger
// because the log package is called concurrently by multiple request,
// X-Request-ID is protected against contamination
func (l *zapLogger) clone() *zapLogger {
lc := *l
return &lc
}
48 changes: 48 additions & 0 deletions internal/pkg/middleware/header.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2023 daz-3ux(杨鹏达) <[email protected]>. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. The original repo for
// this file is https://github.com/Daz-3ux/dBlog.

package middleware

import (
"github.com/gin-gonic/gin"
"net/http"
"time"
)

// NoCache is a Gin middleware used to disable client-side caching of HTTP request response
func NoCache(c *gin.Context) {
c.Header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate, value")
c.Header("Expires", "Thu, 01 Jan 1970 00:00:00 GMT")
c.Header("Last-Modified", time.Now().UTC().Format(http.TimeFormat))
c.Next()
}

// Cors is a Gin middleware used to set the headers for OPTIONS requests
// then exit the middleware chain and complete the request (for handling browser cross-origin requests).
func Cors(c *gin.Context) {
if c.Request.Method != "OPTIONS" {
c.Next()
} else {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
c.Header("Access-Control-Allow-Headers", "authorization, origin, content-type, accept")
c.Header("Access-Control-Allow-Credentials", "false")
c.Header("Access-Control-Max-Age", "600")
c.Header("ALLOW", "HEAD, GET, POST, PUT, PATCH, DELETE, OPTIONS")
c.Header("Content-Type", "application/json")
c.AbortWithStatus(http.StatusNoContent)
}
}

// Secure is a Gin middleware used to add HTTP headers related to security and resource access
func Secure(c *gin.Context) {
c.Header("Access-Control-Allow-Origin", "*")
c.Header("X-Frame-Options", "DENY")
c.Header("X-Content-Type-Options", "nosniff")
c.Header("X-XSS-Protection", "1; mode=block")
if c.Request.TLS != nil {
c.Header("Strict-Transport-Security", "max-age=31536000")
}
}
33 changes: 33 additions & 0 deletions internal/pkg/middleware/requestid.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2023 daz-3ux(杨鹏达) <[email protected]>. All rights reserved.
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file. The original repo for
// this file is https://github.com/Daz-3ux/dBlog.

package middleware

import (
"github.com/Daz-3ux/dBlog/internal/pkg/known"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
)

func RequestID() gin.HandlerFunc {
return func(c *gin.Context) {
// Get the request id from the Gin context
requestID := c.Request.Header.Get(known.XRequestIDKey)

// If the request id is empty, set a new one
if requestID == "" {
requestID = uuid.New().String()
}

// Set the request id to the Gin context
c.Set(known.XRequestIDKey, requestID)

// Set the request id to the response header
c.Writer.Header().Set(known.XRequestIDKey, requestID)

// Continue
c.Next()
}
}

0 comments on commit 942f331

Please sign in to comment.