0%

gin修改请求体或返回body

比如有一个请求,需要先解密,返回的内容需要先加密

可以用gin.HandlerFunc统一处理

// Data是加密的,需要统一解密传给后端业务处理
type Request struct {
    AggEntityID string `json:"AggEntityId"`
    Data        string `json:"Data"`
    TimeStamp   string `json:"TimeStamp"` //yyyyMMddHHmmss
    Seq         string `json:"Seq"`       //0001
    Sig         string `json:"Sig"`       // 参数签名
}
// Data是明文的,需要统一加密返回给请求端
type Response struct {
    Ret  int32  `json:"Ret"`
    Msg  string `json:"Msg"`
    Data string `json:"Data"`
    Sig  string `json:"Sig"`
}

统一处理

import (
    "bytes"
    "encoding/json"
    "gitee.com/njderi/public-plat/internal/vpp/front-gateway/model"
    "github.com/gin-gonic/gin"
    "net/http"
)

// EncryptResponse 返回Response时先加密Data字段
func EncryptResponse() gin.HandlerFunc {
    return func(c *gin.Context) {
        // 创建一个缓冲区来捕获响应
        w := &responseWriter{body: &bytes.Buffer{}, ResponseWriter: c.Writer}
        c.Writer = w

        c.Next()

        if c.Writer.Status() != http.StatusOK {
            return
        }
        // 获取response
        var res model.Response
        if err := json.Unmarshal(w.body.Bytes(), &res); err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read response body"})
            return
        }
        // 修改response
        res.Ret = 1
        res.Msg = "Encrypted Response"
        encryptedBody, err := json.Marshal(res)
        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to marshal encrypted response"})
            return
        }
        // 修改response body
        c.Writer = w.ResponseWriter
        c.Writer.Header().Set("Content-Type", "application/json")
        c.Writer.WriteHeader(http.StatusOK)
        c.Writer.Write(encryptedBody)
    }
}

type responseWriter struct {
    gin.ResponseWriter
    body *bytes.Buffer
}

func (w *responseWriter) Write(b []byte) (int, error) {
    return w.body.Write(b)
}
import (
    "bytes"
    "encoding/json"
    "gitee.com/njderi/public-plat/internal/vpp/front-gateway/model"
    "github.com/gin-gonic/gin"
    "io"
    "io/ioutil"
    "net/http"
)

// DecryptRequest 接收到Request后解密Data字段
func DecryptRequest() gin.HandlerFunc {
    return func(c *gin.Context) {
        if c.Request.Method == http.MethodPost || c.Request.Method == http.MethodPut {
            body, err := io.ReadAll(c.Request.Body)
            if err != nil {
                c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
                c.Abort()
                return
            }

            var req model.Request
            if err := json.Unmarshal(body, &req); err != nil {
                c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request format"})
                c.Abort()
                return
            }

            req.Data = "decrypt(req.Data, key)"

            decryptedBody, err := json.Marshal(req)
            if err != nil {
                c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to marshal decrypted request"})
                c.Abort()
                return
            }

            c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(decryptedBody))
        }
        c.Next()
    }
}
import (
    "github.com/gin-gonic/gin"
)

func SetupAuthGroup(c *gin.Engine) {
    authGroup := c.Group("/vpp/fg/v1")
    // 这个group下所有的接口都会先解密,返回先加密
    authGroup.Use(controller.DecryptRequest())
    authGroup.Use(controller.EncryptResponse())
    {
        authGroup.POST("/query_token", controller.GetToken)
    }
}