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)

相关推荐
h7997103 小时前
go资深之路笔记(八) 基准测试
golang·压力测试
Achou.Wang15 小时前
源码分析 golang bigcache 高性能无 GC 开销的缓存设计实现
开发语言·缓存·golang
虚行15 小时前
Mysql 数据同步中间件 对比
数据库·mysql·中间件
康谋自动驾驶15 小时前
ROS 传感器模块的通用架构设计与跨中间件扩展实践
中间件
奥尔特星云大使15 小时前
mysql读写分离中间件Atlas安装部署及使用
数据库·mysql·中间件·读写分离·atlas
Yeats_Liao17 小时前
Go语言技术与应用(二):分布式架构设计解析
开发语言·分布式·golang
蓝婴天使17 小时前
基于 React + Go + PostgreSQL + Redis 的管理系统开发框架
react.js·postgresql·golang
脚踏实地的大梦想家17 小时前
【Go】P6 Golang 基础:流程控制
开发语言·golang
QX_hao17 小时前
【Go】--数组和切片
后端·golang·restful
-睡到自然醒~17 小时前
提升应用性能:Go中的同步与异步处理
开发语言·后端·golang