3.7 路由控制器
我们看看 beego 的 Controller 结构体源码
type Controller struct {
// context data
Ctx *context.Context // 与输入有关,获取数据
Data map[interface{}]interface{} // 与输出有关
// route controller info
controllerName string
actionName string
methodMapping map[string]func() //method:routertree
AppController interface{}
// template data
TplName string // 与输出有关
ViewPath string
Layout string // 与输出有关
// 与输出有关
LayoutSections map[string]string // the key is the section name and the value is the template name
TplPrefix string
TplExt string
EnableRender bool
// xsrf data
_xsrfToken string
XSRFExpire int
EnableXSRF bool
// session
CruSession session.Store // 于 session 相关
}
//ControllerInterface是统一所有控制器处理程序的接口。
// ControllerInterface is an interface to uniform all controller handler.
type ControllerInterface interface {
// Init 是 beego 在初始化一个控制器的时候调用
Init(ct *context.Context, controllerName, actionName string, app interface{})
// Prepare 每次调用控制器方法的时候会先调用 Prepare
Prepare()
// 请求方法
Get()
// 请求方法
Post()
// 请求方法
Delete()
// 请求方法
Put()
// 请求方法
Head()
// 请求方法
Patch()
// 请求方法
Options()
// 请求方法
Trace()
// 当请求方法执行以后会先调用 Render 方法 然后再调用 Finish
Finish() // 当完成的时候调用的
Render() error // 用来渲染模板
XSRFToken() string
CheckXSRFCookie() bool
HandlerFunc(fn string) bool
URLMapping()
}
这里面就涉及到了 controller 的生命周期,对于 controller 他的执行流程先执行 Prepare
,一般我们不会去写 Init 函数,一般会写 Prepare 函数,接着就是他的各种请求方法,再就是 Render、Finish 。所以我们一般会写的就是 Prepare、Finish
Prepare: 函数执行之前调用,所以我们就可以通过 Prepare 做一些检查,比如说权限的检查,Prepare 可以理解为记录 controller 的时候。
Finish:用来结束 controller 的时候,比如说资源的一些释放。
获取用户提交请求数据:
在 Beego 中获取数据的方式都是对 request 对象的封装
Context => 对应到控制器就是 c.Ctx 对象,c.Ctx 中有以下 3 种方法是和请求数据相关:
-
c.Ctx
-
c.Ctx.Request 类似 http.Request:
-
获取 URL 数据:
-
ParseForm + Form
-
FormValue
-
-
BODY:
-
x-www-form-urlencoded(自定义类型获取):
-
ParseForm + Form
-
ParseForm + PostForm
-
FormValue
-
PostFormValue
-
-
其他
-
Body
-
-
-
-
c.Ctx.Input
Controller 获取请求数据:
-
Get *
3.7.1 Context 获取用户请求数据范例
3.7.1.1 获取用户请求控制器范例
GetControllerAndAction()
方法获取当前请求的控制器和动作
func (c *Controller) GetControllerAndAction() (string, string) {
return c.controllerName, c.actionName
}
package main
import (
"fmt"
"github.com/astaxie/beego"
)
type RequestController struct {
beego.Controller
}
// 获取头里面的信息
func (c *RequestController) Header() {
// GetControllerAndAction() 方法获取当前请求的控制器和动作,返回两个 string
fmt.Println(c.GetControllerAndAction())
c.Ctx.Output.Body([]byte("header"))
}
func main() {
// 绑定自动路由为 RequestController
beego.AutoRouter(&RequestController{})
beego.Run()
}
# curl 请求
[17:28:44 root@go ~]#curl -XPOST "http://127.0.0.1:8080/request/header"
header
# 服务器就会输出 RequestController 控制器中的 Header 方法
[17:25:21 root@go request]#go run main.go
2021/08/07 17:27:47.298 [I] http server Running on http://:8080
RequestController Header
3.7.1.2 获取用户请求行范例
Ctx.Input.Method()
获取用户的请求方法
package main
import (
"fmt"
"github.com/astaxie/beego"
)
type RequestController struct {
beego.Controller
}
// 获取头里面的信息
func (c *RequestController) Header() {
// 获取请求头信息:
// 1.input.Method()获取请求方法
// 2.input.Protocol()获取请求协议,
// 3.input.URL()获取请求 URL
// 4.input.URI()获取请求 URI
// 定义 input 变量,赋值为 c.Ctx.Input
input := c.Ctx.Input
fmt.Println(input.Method(), input.Protocol(), input.URL(), input.URI())
c.Ctx.Output.Body([]byte("header"))
}
func main() {
// 绑定自动路由为 RequestController
beego.AutoRouter(&RequestController{})
beego.Run()
}
# curl 通过 GET 方法请求
[17:55:27 root@go ~]#curl -XGET "http://127.0.0.1:8080/request/header"
header
# curl 通过 post 方法请求
[17:57:58 root@go ~]#curl -XPOST "http://127.0.0.1:8080/request/header"
header[17:58:00 root@go ~]#
# 服务器端输出 post、get 请求方法,和获取请求协议、获取请求 URL、获取请求 URI
[17:55:46 root@go request]#go run main.go
2021/08/07 17:55:47.995 [I] http server Running on http://:8080
GET HTTP/1.1 /request/header /request/header
POST HTTP/1.1 /request/header /request/header
3.7.1.3 获取用户请求头范例
Header 源码
// Header returns request header item string by a given string.
// if non-existed, return empty string.
func (input *BeegoInput) Header(key string) string {
return input.Context.Request.Header.Get(key)
}
范例代码
package main
import (
"fmt"
"github.com/astaxie/beego"
)
type RequestController struct {
beego.Controller
}
// 获取头里面的信息
func (c *RequestController) Header() {
// 定义 input 变量,赋值为 c.Ctx.Input
input := c.Ctx.Input
// 获取 User-Agent 头部信息
fmt.Println(input.Header("User-Agent"))
c.Ctx.Output.Body([]byte("header"))
}
func main() {
// 绑定自动路由为 RequestController
beego.AutoRouter(&RequestController{})
beego.Run()
}
# 通过 curl 浏览器获取到的信息
[18:03:17 root@go request]#go run main.go
2021/08/07 18:03:18.676 [I] http server Running on http://:8080
curl/7.29.0
3.7.1.4 获取用户 RUL 和 Body 中数据
Query 源码
// Query returns input data item string by a given string.
func (input *BeegoInput) Query(key string) string {
if val := input.Param(key); val != "" {
return val
}
if input.Context.Request.Form == nil {
input.dataLock.Lock()
if input.Context.Request.Form == nil {
input.Context.Request.ParseForm()
}
input.dataLock.Unlock()
}
input.dataLock.RLock()
defer input.dataLock.RUnlock()
return input.Context.Request.Form.Get(key)
}
范例代码
package main
import (
"fmt"
"github.com/astaxie/beego"
)
type RequestController struct {
beego.Controller
}
// 获取头里面的信息
func (c *RequestController) Header() {
// 定义 input 变量,赋值为 c.Ctx.Input
input := c.Ctx.Input
// 获取用户 RUL 数据中 id 的数据
fmt.Println(input.Query("id"))
c.Ctx.Output.Body([]byte("header"))
}
func main() {
// 绑定自动路由为 RequestController
beego.AutoRouter(&RequestController{})
beego.Run()
}
客户端请求
# 通过 rul 传递数据 id=1
[18:23:22 root@go ~]#curl -XGET "http://127.0.0.1:8080/request/header/?id=1"
header
# 通过 POST 请求传递 body 中数据 id=4
[18:27:31 root@go ~]#curl -XPOST "http://127.0.0.1:8080/request/header/?id=1" -d "id=4"
header
# 服务器端获取到 id=1 的数据
[18:23:00 root@go request]#go run main.go
2021/08/07 18:23:21.044 [I] http server Running on http://:8080
1 # 获取到用户请求 URL 中数据
4 # 获取到用户请求 Body 中数据
3.7.1.5 通过 Bind 函数获取用户 URL 和 Body 数据
package main
import (
"fmt"
"github.com/astaxie/beego"
)
type RequestController struct {
beego.Controller
}
// 获取头里面的信息
func (c *RequestController) Header() {
// 定义 input 变量,赋值为 c.Ctx.Input
input := c.Ctx.Input
// 通过 Bind 函数获取用户提交数据
// 定义 id 的变量
var id int
// Bind 对用户传入的 URL 或者是 Body 信息中的 id 进行扫描并赋值给 id 变量
input.Bind(&id, "id")
// 输出 id 变量
fmt.Println(id)
c.Ctx.Output.Body([]byte("header"))
}
func main() {
// 绑定自动路由为 RequestController
beego.AutoRouter(&RequestController{})
beego.Run()
}
curl 请求
# POST 请求
[18:27:56 root@go ~]#curl -XPOST "http://127.0.0.1:8080/request/header/?id=1" -d "id=4"
header
# get 请求
[18:31:36 root@go ~]#curl -XGET "http://127.0.0.1:8080/request/header/?id=1"
header
# 服务器端输出 id 信息
[18:31:30 root@go request]#go run main.go
2021/08/07 18:31:31.648 [I] http server Running on http://:8080
4
1
以上就是 Context 对于用户请求头的处理,对于数据这块我们后面更多使用的是 Controller 中的请求处理的方法
3.7.2 Controller 获取用户请求数据范例
数据这块我们后面更多使用的是 Controller 中的请求处理的方法
3.7.2.1 获取用户传入的 URL 和 Body 数据
通过 GetInt 获取用户传入的 URL 和 Body 数据值信息,最常用的就是 GetInt、GetBool、GetString、GetStrings 这几种数据方法
package main
import (
"fmt"
"github.com/astaxie/beego"
)
type RequestController struct {
beego.Controller
}
// 获取头里面的信息
func (c *RequestController) Header() {
// 通过 beego.Controller 获取用户传入的 kye = id 的数据,并且直接将获取到的数据转成 int 类型
fmt.Println(c.GetInt("id"))
c.Ctx.Output.Body([]byte("header"))
}
func main() {
// 绑定自动路由为 RequestController
beego.AutoRouter(&RequestController{})
beego.Run()
}
客户端请求
# Get 请求方法
[18:31:43 root@go ~]#curl -XGET "http://127.0.0.1:8080/request/header/?id=1"
header
# Post 请求方法
[18:42:53 root@go ~]#curl -XPOST "http://127.0.0.1:8080/request/header/?id=1" -d "id=4"
header
# Post 请求并且传递 id 的值为 xxxx 而不是 int 类型,是一个 string 类型,通过 GetString 就能获取
[18:43:03 root@go ~]#curl -XPOST "http://127.0.0.1:8080/request/header/?id=1" -d "id=xxxx"
header
# 服务器端获取到用户请求数据
[18:42:47 root@go request]#go run main.go
2021/08/07 18:42:48.631 [I] http server Running on http://:8080
1 <nil> # 获取到 URL 中 id 的值 nil 表示错误为空
4 <nil> # 获取到 Post 中 id 的值 nil 表示错误为空
0 strconv.Atoi: parsing "xxxx": invalid syntax # 获取到 id=xxxx 值为 0 并报错
3.7.2.2 获取用户提交的所有数据
Controller.Input
就是 http.parseform
package main
import (
"fmt"
"github.com/astaxie/beego"
)
type RequestController struct {
beego.Controller
}
// 获取头里面的信息
func (c *RequestController) Header() {
// Controller.Input 获取用户提交的所有数据信息
fmt.Println(c.Input())
c.Ctx.Output.Body([]byte("header"))
}
func main() {
// 绑定自动路由为 RequestController
beego.AutoRouter(&RequestController{})
beego.Run()
}
curl 访问
# 通过 curl 访问 URL 传递 id=1 并且 Body 传递两个数据 id=xxx&name=zzz
[18:50:25 root@go ~]#curl -XPOST "http://127.0.0.1:8080/request/header/?id=1" -d "id=xxx&name=zzz"
header
# 服务器端响应,拿到用户的 id:[xxx 1] 和 name:[zzz]] 数据
[18:53:33 root@go request]#go run main.go
2021/08/07 18:53:35.557 [I] http server Running on http://:8080
map[id:[xxx 1] name:[zzz]]
3.7.2.3 将用户提交数据解析成结构体(常用)
我们可以将用户的提交数据信息解析为结构体,也就是说一个 ParseForm 对应一个结构体
package main
import (
"fmt"
"github.com/astaxie/beego"
)
type UserLogin struct {
UserName string
Password string
}
type RequestController struct {
beego.Controller
}
// 获取头里面的信息
func (c *RequestController) Header() {
// 定义 form 变量为我们的 UserLogin 类型
var form UserLogin
// 解析的时候可能会出现错误,所以 ParseForm 有一个错误返回值
err := c.ParseForm(&form)
fmt.Println(err, form)
c.Ctx.Output.Body([]byte("header"))
}
func main() {
// 绑定自动路由为 RequestController
beego.AutoRouter(&RequestController{})
beego.Run()
}
curl 请求
# 传递 UserName=zzz&Password=123 的 body 信息
[18:53:54 root@go ~]#curl -XPOST "http://127.0.0.1:8080/request/header/" -d "UserName=zzz&Password=123"
header
# 服务器端响应,输出 {zzz 123} 结构体
[19:04:49 root@go request]#go run main.go
2021/08/07 19:04:52.923 [I] http server Running on http://:8080
<nil> {zzz 123}
但是这里就会有一个问题,代码中结构体的名称和我们提交数据的对应关系是怎么对应的,这个时候其实和 json 类型转的一样的通过 tag 标签进行转换
如果说这个时候用户提交的数据都是小写呢,我们可以看到服务器解析到一个空的结构体,并没有对应上
# 用户提交数据 username=zzz&password=123 小写
[19:07:36 root@go ~]#curl -XPOST "http://127.0.0.1:8080/request/header/" -d "username=zzz&password=123"
header
# 服务器端得到的是一个空的结构体
[19:04:49 root@go request]#go run main.go
2021/08/07 19:04:52.923 [I] http server Running on http://:8080
<nil> { }
这个时候我们就要修改代码在结构体中添加 form 标签
此时用户访问
[19:09:38 root@go ~]#curl -XPOST "http://127.0.0.1:8080/request/header/" -d "username=zzz&password=123"
header
# 服务器端拿到用户提交的 body 结构体
[19:11:10 root@go request]#go run main.go
2021/08/07 19:11:11.884 [I] http server Running on http://:8080
<nil> {zzz 123}