Goframe框架细节

2022-07-11  本文已影响0人  小陈工

一、OmitEmpty空值过滤

空值会影响于写入/更新操作方法,如Insert, Replace, Update, Save操作。

当 map/struct 中存在空值如 nil,"",0 时,默认情况下,gdb将会将其当做正常的输入参数,因此这些参数也会被更新到数据表。

针对空值情况,我们可以通过OmitEmpty方法来过滤掉这些空值。

示例:db.Table("user").OmitEmpty().Data(user).Insert()

二、数据返回-模板解析

Response支持模板文件/内容解析输出,或者模板文件/内容解析返回。与直接使用模板对象解析模板功能不同的是,Response的解析支持一些请求相关的内置变量。模板解析包含以下方法:

WriteTpl*方法用于模板输出,解析并输出模板文件,也可以直接解析并输出给定的模板内容。

ParseTpl*方法用于模板解析,解析模板文件或者模板内容,返回解析后的内容。

解析模板时组件底层会自动通过Request对象获取当前链路的Context上下文变量并传递给模板引擎,因此开发者不用显示给模板引擎传递Context上下文变量。

内置变量:

            1、Config:访问默认的配置管理(config.toml)对象配置项。

                                使用方式:{{.Config.配置项}}

            2、Cookie:访问当前请求的Cookie对象参数值。

                                使用方式:{{.Cookie.键名}}

            3、Session:访问当前请求的Session对象参数值。

                                 使用方式:{{.Session.键名}}

            4、Query:访问当前Query String中的请求参数值。

                                使用方式:{{.Query.键名}}

            5、Form:访问当前表单请求参数值。

                                使用方式:{{.Form.键名}}

            6、Request:访问当前请求参数值(不区分参数提交方式)。

                                使用方式:{{.Request.键名}}

三、请求输入-Context

请求流程往往会在上下文中共享一些自定义设置的变量,例如在请求开始之前通过中间件设置一些变量,随后在路由服务方法中可以获取该变量并相应对一些处理。这种需求非常常见。在GoFrame框架中,我们推荐使用Context上下文对象来处理流程共享的上下文变量,甚至将该对象进一步传递到依赖的各个模块方法中。该Context对象类型实现了标准库的context.Context接口,该接口往往会作为模块间调用方法的第一个参数,该接口参数也是Golang官方推荐的在模块间传递上下文变量的推荐方式。

方法列表:

func(r*Request)GetCtx()context.Context

func(r*Request)SetCtx(ctx context.Context)

func(r*Request)GetCtxVar(keyinterface{},def...interface{})*gvar.Var

func(r*Request)SetCtxVar(keyinterface{},valueinterface{})

简要说明:

GetCtx方法用于获取当前的context.Context对象,作用同Context方法。

SetCtx方法用于设置自定义的context.Context上下文对象。

GetCtxVar方法用于获取上下文变量,并可给定当该变量不存在时的默认值。

SetCtxVar方法用于设置上下文变量。

可以通过SetCtxVar和GetCtxVar来设置和获取自定义的变量,该变量生命周期仅限于当前请求流程。

四、HTTPClient-文件上传

在服务端通过Request对象获取上传文件:

funcUpload(r*ghttp.Request){

files:=r.GetUploadFiles("upload-file")

names,err:=files.Save("/tmp/")

iferr!=nil{

r.Response.WriteExit(err)

}

r.Response.WriteExit("upload successfully: ",names)}

关键代码说明

我们在服务端可以通过r.GetUploadFiles方法获得上传的所有文件对象,也可以通过r.GetUploadFile获取单个上传的文件对象。

在r.GetUploadFiles("upload-file")中的参数"upload-file"为本示例中客户端上传时的表单文件域名称,开发者可以根据前后端约定在客户端中定义,以方便服务端接收表单文件域参数。

通过files.Save可以将上传的多个文件方便地保存到指定的目录下,并返回保存成功的文件名。如果是批量保存,只要任意一个文件保存失败,都将会立即返回错误。此外,Save方法的第二个参数支持随机自动命名上传文件。

通过group.POST("/", Upload)注册的路由仅支持POST方式访问。

文件上传参数格式使用了 参数名=@file:文件路径 ,HTTP客户端将会自动解析文件路径对应的文件内容并读取提交给服务端。原本复杂的文件上传操作被gf进行了封装处理,用户只需要使用 @file:+文件路径 来构成参数值即可。其中,文件路径请使用本地文件绝对路径。

多个文件上传提交参数格式为参数名=@file:xxx&参数名=@file:xxx...,也可以使用参数名[]=@file:xxx&参数名[]=@file:xxx...的形式。

五、Session

任何时候都可以通过ghttp.Request获取Session对象,因为Cookie和Session都是和请求会话相关,因此都属于Request的成员对象,并对外公开。GoFrame框架的Session默认过期时间是24小时。

SessionId默认通过Cookie来传递,并且也支持客户端通过Header传递SessionId,SessionId的识别名称可以通过ghttp.Server的SetSessionIdName进行修改。Session的操作是支持并发安全的,这也是框架在对Session的设计上不采用直接以map的形式操作数据的原因。在HTTP请求流程中,我们可以通过ghttp.Request对象来获取Session对象,并执行相应的数据操作。

gsession模块

Session的管理功能由独立的gsession模块实现,并已完美整合到了ghttp.Server中。由于该模块是解耦独立的,因此可以应用到更多不同的场景中,例如:TCP通信、gRPC接口服务等等。在gsession模块中有比较重要的三个对象/接口:

gsession.Manager:管理Session对象、Storage持久化存储对象、以及过期时间控制。

gsession.Session:单个Session会话管理对象,用于Session参数的增删查改等数据管理操作。

gsession.Storage:这是一个接口定义,用于Session对象的持久化存储、数据写入/读取、存活更新等操作,开发者可基于该接口实现自定义的持久化存储特性。

Session的初始化

以常见的HTTP请求为例。ghttp.Request中的Session对象采用了"懒初始化(LazyInitialization)"设计方式,默认在Request中有一个Session属性对象,但是并未初始化(一个空对象),只有在使用Session属性对象的方法时才会真正执行初始化。这样的设计既保障了未使用Session特性的请求执行性能,也保证了组件使用的易用性。

Session的销毁/注销

用户Session不再使用,例如用户注销登录状态,需要从存储中硬删除,那么可以调用RemoveAll方法。

在默认情况下,ghttp.Server的Session存储使用了内存+文件的方式,使用StorageFile对象实现。具体原理为:

Session的数据操作完全基于内存;

使用gcache进程缓存模块控制数据过期;

使用文件存储持久化存储管理Session数据;

当且仅有当Session被标记为dirty时(数据有更新)才会执行Session序列化并执行文件持久化存储;

当且仅当内存中的Session不存在时,才会从文件存储中反序列化恢复Session数据到内存中,降低IO调用;

序列化/反序列化使用的是标准库的json.Marshal/UnMarshal方法;

六、日志管理

使用配置文件的方式来管理服务配置以及日志配置。 一个参考的日志配置内容示例(以yaml格式为例):

logger:

path:"/var/log/"# 日志文件路径。默认为空,表示关闭,仅输出到终端

file:"{Y-m-d}.log"# 日志文件格式。默认为"{Y-m-d}.log"

prefix:""# 日志内容输出前缀。默认为空

level:"all"# 日志输出级别

ctxKeys:[]# 自定义Context上下文变量名称,自动打印Context的变量到日志中。默认为空

header:true# 是否打印日志的头信息。默认true

stdout:true# 日志是否同时输出到终端。默认true

rotateSize:0# 按照日志文件大小对文件进行滚动切分。默认为0,表示关闭滚动切分特性

rotateExpire:0# 按照日志文件时间间隔对文件滚动切分。默认为0,表示关闭滚动切分特性

rotateBackupLimit:0# 按照切分的文件数量清理切分文件,当滚动切分特性开启时有效。默认为0,表示不备份,切分则删除

rotateBackupExpire:0# 按照切分的文件有效期清理切分文件,当滚动切分特性开启时有效。默认为0,表示不备份,切分则删除

rotateBackupCompress:0# 滚动切分文件的压缩比(0-9)。默认为0,表示不压缩

rotateCheckInterval:"1h"# 滚动切分的时间检测间隔,一般不需要设置。默认为1小时

stdoutColorDisabled:false# 关闭终端的颜色打印。默认开启

writerColorEnable:false# 日志文件是否带上颜色。默认false,表示不带

七、自定义状态码处理

我们可以对WebServer指定的状态码进行自定义处理,例如针对常见的404/403/500等错误,我们可以展示自定义的错误信息、页面内容,或者跳转到一个特定的页面。

我们可以使用BindStatusHandler或者BindStatusHandlerMap来实现针对指定的状态码进行自定义的回调函数处理,并且该特性也支持针对特定的域名绑定。

我们来看几个简单的示例:

s.BindStatusHandler(404,func(r*ghttp.Request){

r.Response.Writeln("This is customized 404 page")

})

执行后,当我们访问没有绑定的路由页面,可以看到,页面显示了我们期望的返回结果:This is customized 404 page。

s.BindStatusHandler(404,func(r*ghttp.Request){

r.Response.RedirectTo("/status/404")

})

执行后,我们手动通过浏览器访问一个不存在的页面,可以看到,页面被引导跳转到了 http://127.0.0.1:8199/status/404 页面,并且可以看到页面返回内容:woops, status 404 found

八、数据校验-校验规则

required

格式: required

说明:必需参数,除了支持常见的字符串,也支持Slice/Map类型。

示例:姓名字段Name为必需参数且不能为空。

typeBizReqstruct{

IDuint`v:"required"`

Namestring`v:"required"`

}

email

格式:email

说明:EMAIL邮箱地址

phone

格式:phone

说明:手机号

phone-loose

格式: phone

说明:宽松的手机号验证,只要满足 13、14、15、16、17、18、19开头的11位数字都可以通过验证。

passport

格式: passport

说明:通用帐号规则(字母开头,只能包含字母、数字和下划线,长度在6~18之间)。

password

格式: password

说明:通用密码规则(任意可见字符,长度在6~18之间)。

json

格式: json

说明:判断数据格式为JSON

same

格式: same:field

说明:参数值必需与field参数的值相同

示例:在用户注册时,提交密码Password和确认密码Password2必须相等(服务端校验)。

typeBizReqstruct{

Namestring`v:"required"`

Passwordstring`v:"required|same:Password2"`

Password2string`v:"required"`

}

regex

格式: regex:pattern

说明:参数值应当满足正则匹配规则pattern

上一篇下一篇

猜你喜欢

热点阅读