golang-gin使用中间件处理文本-时间字符串格式

一、问题

面临的问题:需要对已有业务代码修改时间格式,原本的时间格式里面带了一个T。因为时间分散在各处,又没有统一的管理入口。这面临着大量的代码修改,于是想找一个没有那么大修改量的方式。

二、思路

思考了一下,两个地方是肯定会经过的,一个是JSON转化的地方,一个是中间件。

  1. 在JSON序列化处修改。

如果能添加一个类似Python的encoder之类的东西,那么就可以解决所有的日期的序列化。可惜在一番寻找后,并没有发现这样的东西。其间发现gorm支持在tag上添加序列化,但发现gin是直接使用的原生的json模块,并没有走gorm的逻辑。而原生的json没有统一的修改序列化的地方。

  1. 在中间件处修改。

这个是gin支持的中间件机制。之前有使用过。

  1. monkey patch到time模块上,修改其序列化方法。

直接monkey patch修改原生time类型的序列化方法。这类方法比较脏,不确定是否可能有潜在风险。

三、日志

我上手尝试了一下中间件机制。发现可行就没有再继续验证其它方法。

  1. 创建一个简单的REST API
Go 复制代码
package main
import (
    "regexp"
    "time"
    "github.com/gin-gonic/gin"
)
type StructA struct {
    FieldA string    `form:"field_a"  binding:"required"`
    Ctime  time.Time `form:"ctime" binding:"required"`
}
type StructB struct {
    // 嵌套结构体
    StructA
    FieldB string `form:"field_b"`
}
func GetB(c *gin.Context) {
    // 绑定表单数据至自定义结构体
    var b StructB
    b.Ctime = time.Now()
    c.JSON(200, b)
}
func main() {
    r := gin.Default()
    r.GET("/getb", GetB)
    r.Run()
}
  1. 添加中间件
Go 复制代码
type copyWriter struct {
    gin.ResponseWriter
}
func (cw copyWriter) Write(b []byte) (int, error) {
    // time_re := regexp.MustCompile(`(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}\.\d+)([+-]\d{2}:\d{2})`)
    time_re := regexp.MustCompile(`(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}\.\d{2})\d*([+-]\d{2}:\d{2})`)
    // time_re := regexp.MustCompile(`(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})`)
    s := string(b)
    result := time_re.ReplaceAllString(s, "$1 $2")
    return cw.ResponseWriter.WriteString(result)
}

func main() {
    r := gin.Default()
    r.Use(func(ctx *gin.Context) {
        cw := &copyWriter{ResponseWriter: ctx.Writer}
        ctx.Writer = cw
        ctx.Next()
        // read data in buf
        // do something for data
        // write to ResponseWriter
    })
    r.GET("/getb", GetB)
    r.Run()
}

其中提供了几种不同输出时间格式的正则:

Go 复制代码
    // time_re := regexp.MustCompile(`(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}\.\d+)([+-]\d{2}:\d{2})`)
    time_re := regexp.MustCompile(`(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}\.\d{2})\d*([+-]\d{2}:\d{2})`)
    // time_re := regexp.MustCompile(`(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})`)
  1. 输出结果如下:
Go 复制代码
{
    "FieldA": "",
    "Ctime": "2024-08-19 19:33:42.75",
    "FieldB": ""
}

还可以根据需要,在中间件中增加过滤条件。例如,在仅支持json格式的过滤,防止将文件下载等里的日期也替换掉。

  1. 完整代码
Go 复制代码
package main
import (
    "regexp"
    "time"
    "github.com/gin-gonic/gin"
)
type StructA struct {
    FieldA string    `form:"field_a"  binding:"required"`
    Ctime  time.Time `form:"ctime" binding:"required"`
}
type StructB struct {
    // 嵌套结构体
    StructA
    FieldB string `form:"field_b"`
}
func GetB(c *gin.Context) {
    // 绑定表单数据至自定义结构体
    var b StructB
    b.Ctime = time.Now()
    c.JSON(200, b)
}
type copyWriter struct {
    gin.ResponseWriter
}
func (cw copyWriter) Write(b []byte) (int, error) {
    // time_re := regexp.MustCompile(`(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}\.\d+)([+-]\d{2}:\d{2})`)
    time_re := regexp.MustCompile(`(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2}\.\d{2})\d*([+-]\d{2}:\d{2})`)
    // time_re := regexp.MustCompile(`(\d{4}-\d{2}-\d{2})T(\d{2}:\d{2}:\d{2})`)
    s := string(b)
    result := time_re.ReplaceAllString(s, "$1 $2")
    return cw.ResponseWriter.WriteString(result)
}
func main() {
    r := gin.Default()
    // 创建一个middleware函数,替换返回中的字符串
    r.Use(func(ctx *gin.Context) {
        cw := &copyWriter{ResponseWriter: ctx.Writer}
        ctx.Writer = cw
        ctx.Next()
        // read data in buf
        // do something for data
        // write to ResponseWriter
    })
    r.GET("/getb", GetB)
    r.Run()
}

四、总结

中间件是典型的面向层的,而不是面向对象的思想的产物。利用gin的中间件,基本上可以完成大部分的统一的文本处理需求。

引用:

How to rewrite response body in middleware? · Issue #3384 · gin-gonic/gin (github.com)

相关推荐
有代理ip6 小时前
Python 与 Golang 爬虫的隐藏优势
爬虫·python·golang
天远云服7 小时前
天远车辆过户查询API微服务实战:用Go语言构建高性能车况溯源系统
大数据·微服务·架构·golang
女王大人万岁8 小时前
Go标准库 sync 详解
服务器·开发语言·后端·golang
小高Baby@8 小时前
session、cookie、Jwt-token
开发语言·后端·golang
波波0078 小时前
每日一题:中间件是如何工作的?
中间件·.net·面试题
Grassto9 小时前
12 go.sum 是如何保证依赖安全的?校验机制源码解析
安全·golang·go·哈希算法·go module
玄同7659 小时前
LangChain 1.0 框架全面解析:从架构到实践
人工智能·深度学习·自然语言处理·中间件·架构·langchain·rag
小二·10 小时前
Go 语言系统编程与云原生开发实战(第12篇)云原生部署实战:Helm Chart × GitOps × 多环境管理(生产级落地)
开发语言·云原生·golang
天空属于哈夫克310 小时前
Go 语言实战:构建一个企微外部群“技术贴收藏夹”小程序后端
小程序·golang·企业微信
小二·10 小时前
Go 语言系统编程与云原生开发实战(第13篇)工程效能实战:Monorepo × 依赖治理 × 构建加速(10万行代码实测)
开发语言·云原生·golang