gin 接口开发 - 用户输入自动 TrimSpace

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 大家用过 gin 的就知道,支持指定某个字段为 required 字段必填。然而,我们不能指望用户输入了,这个字段就是可以用的!用户输入了空格,就成功躲避我们的校验,所以我们不得不再校验一次……

最近在思考一个问题,针对用户的输入,能不能快速校验?

比方说下面的 struct,大家用过 gin 的就知道,支持指定某个字段为 required,用户如果不输入,就检验不通过。

type LoginForm struct {
   
    Username string `json:"username" form:"username"`
    Key      string `json:"key" form:"key"`
    Sign     string `json:"sign" form:"sign"`
}

然而,我们不能指望用户输入了,这个字段就是可以用的!例如他提交了这个表单:

{
   
    "username": " ",
    "key": "value",
    "sign": "     "
}

也就是说,用户输入了空格,就成功躲避我们的校验,所以我们不得不再校验一次:

form.Username = strings.TrimSpace(form.Username)
form.Key = strings.TrimSpace(form.Key)
form.Sign = strings.TrimSpace(form.Sign)

……显然,非常不优雅!如果字段多的话,满屏都是这样子的代码,相信屏幕前的你也是受不了的!

那有没有好办法?

因为公司存在 PHP 业务,为了兼容,JSON 的解析使用了 jsoniter 这个第三方包。如果你也是使用 gin 框架,别忘了编译指定 -tags=jsoniter 构建标签:

go build -tags=jsoniter -o ./${PROJECT_NAME} ./cmd/server

而 jsoniter 有个非常强大的功能,支持在解析类型的时候,执行你给定的钩子!

于是只要我们在项目启动的时候注册以下钩子函数:

当解析到 string 的时候,自动帮我们 TrimSpace !!!

func init() {
   
    jsonAutoTrimSpace()
}

func jsonAutoTrimSpace() {
   
    jsoniter.RegisterTypeDecoderFunc("string", func(ptr unsafe.Pointer, iter *jsoniter.Iterator) {
   
        s := strings.TrimSpace(iter.ReadString())
        *((*string)(ptr)) = s
    })
}

至此,JSON 数据解析的时候,就支持自动去掉空白字符了。但是有时候参数不是 JSON 传递的,是通过 URL 的参数形式、或者是 POST 表单,该怎么办?

这个大家可以看下 http.RequestParseFormParseMultipartForm 方法,它只会解析一次。

而 gin 底层的 Bind 也是调用了这两个方法,我们可以在用户 Bind 之前,调用 ParseForm 和 ParseMultipartForm 方法,对里面的 Value 遍历并 TrimSpace 就好了!后面用户第二次调用,拿到的也是我们 TrimSpace 后的内容了。

func shouldBindForm(req *http.Request) (err error) {
   
    if err = req.ParseForm(); err != nil {
   
        return
    }
    const defaultMemory = 32 << 20
    if err = req.ParseMultipartForm(defaultMemory); err != nil {
   
        if err == http.ErrNotMultipart {
   
            err = nil
        } else {
   
            return
        }
    }
    for k, v := range req.Form {
   
        for i, s := range v {
   
            req.Form[k][i] = strings.TrimSpace(s)
        }
    }
    for k, v := range req.PostForm {
   
        for i, s := range v {
   
            req.PostForm[k][i] = strings.TrimSpace(s)
        }
    }
    if req.MultipartForm != nil {
   
        for k, v := range req.MultipartForm.Value {
   
            for i, s := range v {
   
                req.MultipartForm.Value[k][i] = strings.TrimSpace(s)
            }
        }
    }
    return
}

shouldBindForm 的调用时机,需要检查一下 ContentType,如果是表单,或者是 GET 请求,就执行一下,具体可以参考 gin 的实现。


文章来源于本人博客,发布于 2019-09-08,原文链接:https://imlht.com/archives/193/

目录
相关文章
|
5月前
|
存储 JSON 前端开发
gin框架学习笔记(四) ——参数绑定与参数验证
gin框架学习笔记(四) ——参数绑定与参数验证
121 0
|
数据安全/隐私保护
fastadmin中写接口是时Validate规则验证自定义如何用
fastadmin中写接口是时Validate规则验证自定义如何用
208 0
|
6月前
uni-app 76聊天类封装(十一)-更新会话列表(二)
uni-app 76聊天类封装(十一)-更新会话列表(二)
41 1
|
11月前
|
前端开发 API Python
DRF自定义错误异常替换detail信息
因为自己写api定义了一套格式,但是django rest_framework的异常提醒又跟我的不一样, 要么是:
47 2
|
6月前
|
Oracle Java 关系型数据库
Generator【SpringBoot集成】代码生成+knife4j接口文档(2种模板设置、逻辑删除、字段填充 含代码粘贴可用)保姆级教程(注意事项+建表SQL+代码生成类封装+测试类)
Generator【SpringBoot集成】代码生成+knife4j接口文档(2种模板设置、逻辑删除、字段填充 含代码粘贴可用)保姆级教程(注意事项+建表SQL+代码生成类封装+测试类)
104 0
|
安全 测试技术 Go
Go 1.18 新增三大功能之一“模糊测试”使用方式
Go 1.18 新增三大功能之一“模糊测试”使用方式
50 0
|
缓存 NoSQL 前端开发
【Go】基于 Gin 从0到1搭建 Web 管理后台系统后端服务(三)路由、自定义校验器和 Redis
【Go】基于 Gin 从0到1搭建 Web 管理后台系统后端服务(三)路由、自定义校验器和 Redis
|
前端开发
前端hook项目pc总结笔记-postgrest方法拼接扩展
前端hook项目pc总结笔记-postgrest方法拼接扩展
100 0
前端hook项目pc总结笔记-postgrest方法拼接扩展
|
开发框架 JSON 前端开发
【C#】.net core2.1,自定义全局类对API接口和视图页面产生的异常统一处理
在开发一个网站项目时,异常处理和过滤功能是最基础的模块 本篇文章就来讲讲,如何自定义全局异常类来统一处理
237 0
|
存储 数据安全/隐私保护
CE修改器入门:代码替换功能
某些游戏重新开始时,数据会存储在与上次不同的地方, 甚至游戏的过程中数据的存储位置也会变动。在这种情况下,你还是可以简单几步搞定它。这次我将尽量阐述如何运用"代码替换"功能,第五关的数值每次启动教程的时候都会存放在内存不同的位置,所以地址列表中的固定地址是不起作用的。
401 0
CE修改器入门:代码替换功能