Gin 基础
参考:
go module介绍 (官方文档)
go module是go官方自带的go依赖管理库,在1.13版本正式推荐使用。
go module可以将某个项目(文件夹)下的所有依赖整理成一个 go.mod 文件,里面写入了依赖的版本等。
使用go module之后我们可不用将代码放置在src下了。
使用 go module 管理依赖后会在项目根目录下生成两个文件 go.mod 和 go.sum。go..mod用来标记一个module和当前依赖以及依赖库的版本,go.sum 记录每个依赖库的版本和哈希值。
开启 go Module
// windows
set GO111MODULE=on
// mac
export GO111MODULE=on初始化
创建项目: day01
gin 安装
示例
第一个 gin 程序
初始工作
代码书写
AsciiJSON
使用 AsciiJSON 生成具有转义的非 ASCII 字符的 ASCII-only JSON。
RESTful API
REST的含义就是客户端与Web服务器之间进行交互的时候,使用HTTP协议中的4个请求方法代表不同的动作。
GET用来获取资源POST用来新建资源PUT用来更新资源DELETE用来删除资源。
示例
HTML 渲染
使用 LoadHTMLGlob() 或者 LoadHTMLFiles()
templates/index.tmpl
使用不同目录下名称相同的模板
templates/posts/index.tmpl
templates/users/index.tmpl
自定义模板渲染器
要指定所有的html路径,不推荐
自定义模板函数
定义一个不转义相应内容的safe模板函数如下:
在index.tmpl中使用定义好的safe模板函数:
自定义分隔符
使用自定义分隔
自定义模板功能
raw.tmpl
静态文件处理
当我们渲染的HTML文件中引用了静态文件时,我们只需要按照以下方式在渲染页面前调用gin.Static方法即可。
使用模板继承
Gin框架默认都是使用单模板,如果需要使用block template功能,可以通过"github.com/gin-contrib/multitemplate"库实现,具体示例如下:
首先,假设我们项目目录下的templates文件夹下有以下模板文件,其中home.tmpl和index.tmpl继承了base.tmpl:
然后我们定义一个loadTemplates函数如下:
我们在main函数中
补充文件路径处理
关于模板文件和静态文件的路径,我们需要根据公司/项目的要求进行设置。可以使用下面的函数获取当前执行程序的路径
JSON渲染
XML渲染
YMAL渲染
protobuf渲染
XML/JSON/YAML/ProtoBuf 等常见渲染方法,以及其测试结果。
此处 protoexample.Test 结构体在 github.com/gin-gonic/gin/testdata/protoexample 中,具体格式如下:
测试:
获取参数
通过Query方法可以获取url 中? 之后的请求参数 通过PostForm方法可以获取到 Post 的数据。
获取querystring参数
querystring指的是URL中?后面携带的参数,例如:/user/search?username=小王子&address=沙河。 获取请求的querystring参数的方法如下:
获取form参数
当前端请求的数据通过form表单提交时,例如向/user/search发送一个POST请求,获取请求数据的方式如下:
获取json参数
当前端请求的数据通过JSON提交时,例如向/json发送一个POST请求,则获取请求参数的方式如下:
更便利的获取请求参数的方式,参见下面的 参数绑定 小节。
获取path参数
请求的参数通过URL路径传递,例如:/user/search/小王子/沙河。 获取请求URL路径中的参数的方式如下。
参数绑定
为了能够更方便的获取请求相关参数,提高开发效率,我们可以基于请求的Content-Type识别请求数据类型并利用反射机制自动提取请求中QueryString、form表单、JSON、XML等参数到结构体中。 下面的示例代码演示了.ShouldBind()强大的功能,它能够基于请求自动提取JSON、form表单和QueryString类型的数据,并把值绑定到指定的结构体对象。
ShouldBind会按照下面的顺序解析请求中的数据完成绑定:
如果是
GET请求,只使用Form绑定引擎(query)。如果是
POST请求,首先检查content-type是否为JSON或XML,然后再使用Form(form-data)。
文件上传返回
单个文件上传
文件上传前端页面代码:
后端gin框架部分代码:
多个文件上传
MultipartForm:MultipartForm是经过解析的多部分表单(表单里面只有两个属性Value和File),包括文件上传。
File: File部分存储在内存或磁盘上,可通过*FileHeader的Open方法访问。
Value: Value部分存储为字符串。
两者都通过map的字段名进行键控。
给前端返回文件
二进制流的方式
重定向
专业防封技术
简单来讲,专业防封就是通过技术手段的处理让你的域名可以绕过微信系统检测。技术处理部分如下:
1、域名备案(大站或者不同主体独立备案域名) 2、跳转方式(超级中转圆滑跳到落地页) 3、敏感词处理(混淆敏感词,绕过检测) 4、随机ip(可用cdn加速技术,使得ip在各省各区都不同) 5、来源处理(跳转去除来源,使得入口链接不受牵连)
模型绑定
绑定表单或者查询字符串
在结构体Name字段声明form标签,并调用ShouldBindQuery方法,gin会为我们绑定查询字符串中的name和address两个参数。 注意虽然我们声明了form标签,ShouldBindQuery只绑定查询字符串中的参数。 如果你想绑定表单中的参数的话结构体不用改变,需要把ShouldBindQuery方更改为ShouldBind方法。 ShouldBind 方法会区分GET和POST请求,如果是GET请求绑定查询字符串中的参数,如果是POST请求绑定表单参数中的内容,但是不能同时绑定两种参数。
绑定json参数
gin绑定json格式数据方法很简单,只需要设置字段的标签为 json 并且调用ShouldBind方法。
其他类型参数绑定
路由参数在绑定时设置标签为uri,并调用ShouldBindUri方法。
绑定在HTTP Header中的参数,字段的标签设置为header,调用方法为ShouldBindHeader。 还有不太常用的数组参数是字段标签设置为form:"colors[]",结构体例子如下:
文件上传这种场景我很少用模型绑定的方式获取参数,在gin中对于这种场景也提供了模型绑定支持。
多种类型的模型绑定
如果我们有一个UpdateUser接口,PUT /user/:id,参数是{"nickname": "nickname...","mobile": "13322323232"}。代码如下:
参数验证
gin框架使用 github.com/go-playground/validator 进行参数校验,
字符串约束
excludesall:不包含参数中任意的 UNICODE 字符,例如excludesall=ab;
excludesrune:不包含参数表示的 rune 字符,excludesrune=asong;
startswith:以参数子串为前缀,例如startswith=hi;
endswith:以参数子串为后缀,例如endswith=bye。
contains=:包含参数子串,例如contains=email;
containsany:包含参数中任意的 UNICODE 字符,例如containsany=ab;
containsrune:包含参数表示的 rune 字符,例如`containsrune=asong;
excludes:不包含参数子串,例如excludes=email;
范围约束
ne:不等于参数值,例如ne=5;
gt:大于参数值,例如gt=5;
gte:大于等于参数值,例如gte=50;
lt:小于参数值,例如lt=50;
lte:小于等于参数值,例如lte=50;
oneof:只能是列举出的值其中一个,这些值必须是数值或字符串,以空格分隔,如果字符串中有空格,将字符串用单引号包围,例如oneof=male female。
eq:等于参数值,注意与len不同。对于字符串,eq约束字符串本身的值,而len约束字符串长度。例如eq=10;
len:等于参数值,例如len=10;
max:小于等于参数值,例如max=10;
min:大于等于参数值,例如min=10
Fields约束
eqfield:定义字段间的相等约束,用于约束同一结构体中的字段。例如:eqfield=Password
eqcsfield:约束统一结构体中字段等于另一个字段(相对),确认密码时可以使用,例如:eqfiel=ConfirmPassword
nefield:用来约束两个字段是否相同,确认两种颜色是否一致时可以使用,例如:nefield=Color1
necsfield:约束两个字段是否相同(相对)
常用约束
unique:指定唯一性约束,不同类型处理不同:
对于map,unique约束没有重复的值
对于数组和切片,unique没有重复的值
对于元素类型为结构体的碎片,unique约束结构体对象的某个字段不重复,使用unique=field指定字段名
email:使用email来限制字段必须是邮件形式,直接写eamil即可,无需加任何指定。
omitempty:字段未设置,则忽略
-:跳过该字段,不检验;
|:使用多个约束,只需要满足其中一个,例如rgb|rgba;
required:字段必须设置,不能为默认值;
更多参考
https://pkg.go.dev/github.com/go-playground/validator/v10
快速安装
示例一
示例二
自定义结构体校验
例如现在有一个需求,存在db的用户信息中创建时间与更新时间都要大于某一时间,假设是从前端传来的(
Gin路由
普通路由
此外,还有一个可以匹配所有请求方法的Any方法如下:
为没有配置处理函数的路由添加处理程序,默认情况下它返回404代码,下面的代码为没有匹配到路由的请求都返回views/404.html页面。
路由组和嵌套
将拥有共同URL前缀的路由划分为一个路由组 通常我们将路由分组用在划分业务逻辑或划分API版本时。
路由组嵌套
Gin中间件
类似钩子函数
定义中间件
Gin中的中间件必须是一个gin.HandlerFunc类型。例如我们像下面的代码一样定义一个统计请求耗时的中间件。
注册中间件
在gin框架中,我们可以为每个路由添加任意数量的中间件。
为全局路由注册
为某个路由单独注册
为路由组注册中间件
为路由组注册中间件有以下两种写法。
中间件注意事项
gin默认中间件
gin.Default()默认使用了Logger和Recovery中间件,其中:
Logger中间件将日志写入gin.DefaultWriter,即使配置了GIN_MODE=release。
Recovery中间件会recover任何panic。如果有panic的话,会写入500响应码。
如果不想使用上面两个默认的中间件,可以使用gin.New()新建一个没有任何默认中间件的路由。
gin中间件中使用goroutine 当在中间件或handler中启动新的goroutine时,不能使用原始的上下文(c *gin.Context),必须使用其只读副本(c.Copy())。
运行多个服务
我们可以在多个端口启动服务,例如:
其他
SecureJSON
使用 SecureJSON 防止 json 劫持。 如果给定的结构是数组值,则默认预置 “while(1),” 到响应体。
HTTP2 server 推送
服务器推送(server push)指的是,还没有收到浏览器的请求,服务器就把各种资源推送给浏览器。比如,浏览器只请求了index.html,但是服务器把index.html、style.css、example.png全部发送给浏览器。这样的话,只需要一轮 HTTP 通信,浏览器就得到了全部资源,提高了性能
assets/app.js
JSONP 回调
使用 JSONP 向不同域的服务器请求数据。
如果查询参数存在回调,则将回调添加到响应体中。
Multipart/Urlencoded 绑定
用户 post 指定数据后,如符合要求则给出对应的输出
Multipart/Urlencoded 表单
通过表单功能可以读出浏览器冲传入的参数。
PureJSON 特殊字符转换
JSON 使用 unicode 替换特殊 HTML 字符,例如 < 变为 \ u003c。 如果要按字面对这些字符进行编码,则可以使用 PureJSON。 Go 1.6 及更低版本无法使用此功能。
SecureJSON
使用 SecureJSON 防止 json 劫持。 如果给定的结构是数组值,则默认预置 “while(1),” 到响应体。
从 reader 读取文件
从远程读取文件,下载下来
优雅地重启或停止
替代方案:
manners:可以优雅关机的 Go Http 服务器。
graceful:Graceful 是一个 Go 扩展包,可以优雅地关闭 http.Handler 服务器。
grace:Go 服务器平滑重启和零停机时间部署。
如果你使用的是 Go 1.8,可以不需要这些库!
使用 BasicAuth 中间件
使用 HTTP 方法
自定义 HTTP 服务器配置
使用中间件
不使用默认的中间件
Last updated