Versions Compared
Key
- This line was added.
- This line was removed.
- Formatting was changed.
请求输入依靠 ghttp.Request
对象实现,ghttp.Request
继承了底层的http.Request
对象。ghttp.Request
包含一个与当前请求对应的返回输出对象Response
,用于数据的返回处理。
相关方法: https://pkg.go.dev/github.com/gogf/gf/v2/net/ghttp#Request
简要说明
可以看到Request
对象的参数获取方法非常丰富,可以分为以下几类:对象的参数获取方法非常丰富,常用方法如下:
常用方法 | 描述 |
---|---|
Get |
常用方法,简化参数获取, | |
GetQuery |
获取GET 方式传递过来的参数,包括Query String 及Body 参数解析。 | |
GetForm |
获取表单方式传递过来的参数,表单方式提交的参数Content-Type 往往为application/x-www-form-urlencoded , application/form-data , multipart/form-data , multipart/mixed 等等。 | |
GetRequest |
获取客户端提交的所有参数,按照参数优先级进行覆盖,不区分提交方式。 | |
Get*Struct |
将指定提交类型的所有请求参数绑定到指定的struct 对象上,注意给定的参数为对象指针。绝大部分场景中往往使用Parse 方法将请求数据转换为请求对象,具体详见后续章节。 | |
GetBody/GetBodyString |
获取客户端提交的原始数据,该数据是客户端写入到body 中的原始数据,与HTTP Method 无关,例如客户端提交JSON/XML 数据格式时可以通过该方法获取原始的提交数据。 | |
GetJson |
自动将原始请求信息解析为gjson.Json 对象指针返回,gjson.Json 对象具体在 通用编解码-gjson 章节中介绍。 | |
Exit* |
用于请求流程退出控制,详见本章后续说明。 |
提交方式
GoFrame
框架的参数获取不是通过HTTP Method
来做区分,而是通过参数提交类型来区分。例如,分别通过HTTP Method: POST、INPUT、DELETE
来提交表单参数,在服务端获取参数不是通过GetPost
/GetInput
/GetDelete
的方式来获取,而是统一通过GetForm
方法来获取表单参数,针对其他的HTTP Method
也是如此。
在GoFrame
框架下,有以下几种提交类型:
提交类型 | 描述 |
---|---|
Router | 路由参数。来源于路由规则匹配。 |
Query |
|
Form | 表单参数。最常见的提交方式,提交的 |
Body | 内容参数。从 |
Custom | 自定义参数,往往在服务端的中间件、服务函数中通过 |
参数类型
获取的参数方法可以对指定键名的数据进行自动类型转换,例如:获取的参数方法可以对指定键名的数据进行自动类型转换,例如:http://127.0.0.1:8199/?amount=19.66
,通过Get(xxx).String()
将会返回19.66
的字符串类型,Get(xxx).Float32()
/Get(xxx).Float64()
将会分别返回float32
和float64
类型的数值19.66
。但是,Get(xxx).Int()
/Get(xxx).Uint()
将会返回19
(如果参数为float
类型的字符串,将会按照向下取整进行整型转换)。
Tip |
---|
聪明的您一定发现了,获取到的参数都是泛型变量,根据该泛型变量再根据需要调用对应的方法转换为对应的数据类型。聪明的您一定发现了,获取到的参数都是泛型变量,根据该泛型变量再根据需要调用对应的方法转换为对应的数据类型。 |
使用示例:
Code Block | ||
---|---|---|
| ||
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("amount").String()) r.Response.Writeln(r.Get("amount").Int()) r.Response.Writeln(r.Get("amount").Float32()) }) s.SetPort(8199) s.Run() } |
执行后我们访问地址 http://127.0.0.1:8199/?amount=19.66 页面输出
Code Block | ||
---|---|---|
| ||
19.66 19 19.66 |
参数优先级
我们考虑一种场景,当不同的提交方式中存在同名的参数名称会怎么样?在GoFrame
框架下,我们根据不同的获取方法,将会按照不同的优先级进行获取,优先级高的方式提交的参数将会优先覆盖其他方式的同名参数。优先级规则如下:
Get
及GetRequset
方法:Router < Query < Body < Form < Custom
,也就是说自定义参数的优先级最高,其次是Form
表单参数,再次是Body
提交参数,以此类推。例如,Query
和Form
中都提交了同样名称的参数id
,参数值分别为1
和2
,那么Get("id")
/GetForm("id")
将会返回2
,而GetQuery("id")
将会返回1
。GetQuery
方法:Query > Body
,也就是说query string
的参数将会覆盖Body
中提交的同名参数。例如,Query
和Body
中都提交了同样名称的参数id
,参数值分别为1
和2
,那么Get("id")
将会返回2
,而GetQuery("id")
将会返回1
。GetForm
方法:由于该类型的方法仅用于获取Form
表单参数,因此没什么优先级的差别。
使用示例:
Code Block | ||
---|---|---|
| ||
package main import ( "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" ) func main() { s := g.Server() s.BindHandler("/input", func(r *ghttp.Request) { r.Response.Writeln(r.Get("amount")) }) s.BindHandler("/query", func(r *ghttp.Request) { r.Response.Writeln(r.GetQuery("amount")) }) s.SetPort(8199) s.Run() } |
执行后,我们通过curl
工具进行测试:
Code Block | ||
---|---|---|
| ||
$ curl -d "amount=1" -X POST "http://127.0.0.1:8199/input?amount=100" 1 $ curl -d "amount=1" -X POST "http://127.0.0.1:8199/query?amount=100" 100 |
可以看到,当我们访问/input
路由时,该路由方法中采用了Get
方法获取amount
参数,按照同名优先级的规则返回了1
,即body
中传递的参数。而当我们通过/query
路由访问时,该路由方法内部使用了GetQuery
方法获取amount
参数,因此获取到的是query string
参数中的amount
值,返回了100
。
大小写敏感
需要注意哦,参数名称是大小写敏感的哦,例如客户端提交的参数name
和Name
是两个参数。 由于服务端默认是通过字符串名称获取参数,因此大小写敏感并不会产生什么问题,但是如果服务端接收的是一个API对象,那么可能需要注意一下。我们来看一个例子。
服务端:
Code Block | ||
---|---|---|
| ||
package main import ( "context" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" ) type Controller struct{} type PathReq struct { g.Meta `path:"/api/v1/*path" method:"post"` Path string } type PathRes struct { Path string } func (c *Controller) Path(ctx context.Context, req *PathReq) (res *PathRes, err error) { return &PathRes{Path: req.Path}, nil } func main() { s := g.Server() s.SetPort(8199) s.Use(ghttp.MiddlewareHandlerResponse) s.Group("/", func(group *ghttp.RouterGroup) { group.Bind(&Controller{}) }) s.Run() } |
服务端的接口设计原意是定义一个路由参数path
,并且通过API
对象的Path
属性来接收。
客户端:
Code Block | ||
---|---|---|
| ||
package main import ( "fmt" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gctx" ) func main() { var ( ctx = gctx.New() client = g.Client() ) client.SetPrefix("http://127.0.0.1:8199") for i := 0; i < 10; i++ { fmt.Println(client.PostContent(ctx, "/api/v1/user/info", `{"Path":"user/profile"}`)) } } |
根据我们的理解,客户端提交后,服务端应该会收到路由参数path
的值为user/info
。但是很奇怪,由于程序BUG
,客户端提交的Body
中同样提交了一个JSON
,参数名称为Path
,参数值为user/profile
。那么这个时候服务端API
对象中的属性Path
将会是哪个值呢?
我们将客户端反复执行多次,发现输出的结果都是:
Code Block | ||
---|---|---|
| ||
{"code":0,"message":"","data":{"Path":"user/profile"}} {"code":0,"message":"","data":{"Path":"user/profile"}} {"code":0,"message":"","data":{"Path":"user/profile"}} {"code":0,"message":"","data":{"Path":"user/profile"}} {"code":0,"message":"","data":{"Path":"user/profile"}} {"code":0,"message":"","data":{"Path":"user/profile"}} {"code":0,"message":"","data":{"Path":"user/profile"}} {"code":0,"message":"","data":{"Path":"user/profile"}} {"code":0,"message":"","data":{"Path":"user/profile"}} {"code":0,"message":"","data":{"Path":"user/profile"}} |
即参数都是Body
中提交的值,而不是路由参数中的值。其实,由于参数大小写敏感的缘故,服务端这个时候接受到了两个参数,一个是路由参数path
,一个是Body JSON
提交的Path
。服务端在转换API
参数对象的时候,由于属性Path
和Body JSON
中提交的Path
更匹配,因此,使用的是Body JSON
中的Path
的值。
继续了解
Children Display | ||||
---|---|---|---|---|
|
Panel | ||
---|---|---|
| ||
|