GoFrame day3
前言
上一次总结了路由相关的内容,今天就接着继续总结.当我们访问某个api的时候往往需要根据路由请求带有的参数来实现内部的操作,所以来看看怎么获得参数以及进行数据返回.
请求输入
我们在路由注册的时候都依靠ghttp.Request
对象来实现页面操作处理,我们也可以通过这个对象的方法获得请求参数.
在ghttp_request_param.go
中可以看到相关的方法,并且看源码中所有的值都是...interface{}
也就是最近推出的any
,使得每个解析出来的参数值都是泛型变量.最简单的获取路由参数例子如下
package main import ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" ) func main() { s := g.Server() s.BindHandler("/", func(r *ghttp.Request) { r.Response.Writeln(r.Get("xxx").String()) }) s.SetPort(8080) s.Run() } 复制代码
复杂参数
当我们请求的参数较为复杂时,对应不同的情况会有不同的解析结果,下面就是各种情况的总结
参数 | 结果 |
k=m&k=n |
map[k:n] |
k1=m&k2=n |
map[k1:m k2:n] |
k[]=m&k[]=n |
map[k:[m n]] |
k[a][]=m&k[a][]=n |
map[k:map[a:[m n]]] |
k[a]=m&k[b]=n |
map[k:map[a:m b:n]] |
k[a][a]=m&k[a][b]=n |
map[k:map[a:map[a:m b:n]]] |
k=m&k[a]=n |
error |
对象处理
一般将输入输出定义为结构体对象,并且提交的参数可以很好的映射到预先定义的结构体属性上.默认的转换规则如下
struct
中需要匹配的属性必须为**公开属性
**(首字母大写)。- 参数名称会自动按照
不区分大小写
且 忽略-/_/空格
符号 的形式与struct
属性进行匹配。 - 如果匹配成功,那么将键值赋值给属性,如果无法匹配,那么忽略该键值。
当然我们为了简单也可以自定义参数的映射规则,使用aaa typename p:"xxx"
可以将xxx
映射到结构体aaa
属性上
package main import ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" ) type RegisterReq struct { Name string Pass string `p:"password1"` Pass2 string `p:"password2"` } type RegisterRes struct { Code int `json:"code"` Error string `json:"error"` Data interface{} `json:"data"` } func main() { s := g.Server() s.BindHandler("/register", func(r *ghttp.Request) { var req *RegisterReq if err := r.Parse(&req); err != nil { r.Response.WriteJsonExit(RegisterRes{ Code: 1, Error: err.Error(), }) } // ... r.Response.WriteJsonExit(RegisterRes{ Data: req, }) }) s.SetPort(8080) s.Run() } 复制代码
请求校验
GoFrame有强大的请求校验功能,可以给我们定义的结构体绑定v
标签来实现参数校验.但是貌似这里有个bug问题,如果我们利用自定义的swagger加上v
标签校验的话就会导致验证错误,无法使用try it out.当然也有其他人遇到了这个问题,具体可以看看这个issue,目前这个bug已经在2.1.0-rc4
中被修复,希望下一个版本的GoFrame能更加完美.
默认值
当我们需要设置默认值的时候,可以在结构体的属性中添加d
标签
数据返回
当我们处理完请求参数,可以利用请求参数实现一些逻辑,但是最终还是要返回结果给页面,这个时候就需要利用一些数据返回接口了.
缓冲控制
Response
输出采用了缓冲控制,输出的内容预先写入到一块缓冲区,等待服务方法执行完毕后才真正地输出到客户端。该特性在提高执行效率同时为输出内容的控制提供了更高的灵活性。
当服务出现异常时,通常需要将错误信息对用户隐藏,转而设置为统一的错误信息,这个时候可以利用中间件的后置处理,将异常信息清除并转为提示信息输出
package main import ( "net/http" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" ) func MiddlewareErrorHandler(r *ghttp.Request) { r.Middleware.Next() if r.Response.Status >= http.StatusInternalServerError { r.Response.ClearBuffer() r.Response.Writeln("服务器居然开小差了,请稍后再试吧!") } } func main() { s := g.Server() s.Group("/api.v2", func(group *ghttp.RouterGroup) { group.Middleware(MiddlewareErrorHandler) group.ALL("/user/list", func(r *ghttp.Request) { panic("db error: sql is xxxxxxx") }) }) s.SetPort(8080) s.Run() }
当然也可以试试清除缓冲区和不清除缓冲区的区别
重定向
更多时候需要实现一些页面跳转功能,这个时候就需要用到重定向.
RedirectTo()
可以将页面重定向到另外一个路由RedirectBack()
返回上一个页面
下面就简单实现一个页面跳转的demo
package main import ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" ) func main() { s := g.Server() s.BindHandler("/", func(r *ghttp.Request) { r.Response.RedirectTo("/login") }) s.BindHandler("/login", func(r *ghttp.Request) { r.Response.Writeln(`<a href="/home">Redirect to home</a>`) }) s.BindHandler("/home", func(r *ghttp.Request) { r.Response.Writeln(`<a href="/login">Back to login</a>`) //r.Response.RedirectBack() }) s.SetPort(8080) s.Run() } 复制代码
可以试试加与不加RedirectBack()
的效果
文件下载
可以使用ServeFile
与ServeFileDownload
分别实现文件展示,文件格式识别与下载
package main import ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" ) func main() { s := g.Server() s.BindHandler("/show", func(r *ghttp.Request) { r.Response.ServeFile("test.txt") }) s.BindHandler("/download", func(r *ghttp.Request) { r.Response.ServeFileDownload("test.txt") }) s.SetPort(8080) s.Run() }
下载页面会直接弹出文件下载框,大家可以自己访问看效果
最后
今天这里总结了大部分的常用处理,但是留了一个小坑—文件上传部分的内容留到下次单独讲.