- Created by 郭强, last modified on Mar 25, 2022
请求输入依靠 ghttp.Request
对象实现,ghttp.Request
继承了底层的http.Request
对象。ghttp.Request
包含一个与当前请求对应的返回输出对象Response
,用于数据的返回处理。
相关方法: https://pkg.go.dev/github.com/gogf/gf/v2/net/ghttp#Request
简要说明
可以看到Request
对象的参数获取方法非常丰富,可以分为以下几类:
Get
: 常用方法,简化参数获取,GetRequest
的别名。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
:URL
中的Query String
参数解析,如:http://127.0.0.1/index?id=1&name=john
中的id=1&name=john
。Form
: 表单提交参数,最常见的提交方式,提交的Content-Type
往往为:application/x-www-form-urlencoded
、multipart/form-data
、multipart/mixed
。Body
: 原始提交内容,从Body
中获取并解析得到的参数,JSON
/XML
请求往往使用这种方式提交。Custom
: 自定义参数,往往在服务端的中间件、服务函数中通过SetParam/GetParam
方法管理。
参数类型
获取的参数方法可以对指定键名的数据进行自动类型转换,例如: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
类型的字符串,将会按照向下取整进行整型转换)。
聪明的您一定发现了,获取到的参数都是泛型变量,根据该泛型变量再根据需要调用对应的方法转换为对应的数据类型。
使用示例:
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 页面输出
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
表单参数,因此没什么优先级的差别。
使用示例:
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
工具进行测试:
$ 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
。
继续了解:
- No labels
19 Comments
LIN PENG
大神,请问怎么判断用户是否传了某个参数?
实际开发过程中有这个个需求:
1、用户传了某个参数才会修改,不传不修改。
2、如果用户不传获取到的参数是空(字符串举例)
3、如果用户传空拿到的也是空,就无法区分用户到底是想修改成空,还不不想修改。
打印结果:
remark: &v false
前端请求:
郭强
有多种方式,常见的方法是:
1、可以通过
r.GetForm("remark") == nil
判断客户端是否有提交remark
参数。2、如果你定义对象接受参数,那么将对象的指定属性值定义为指针即可,例如:
随后使用
r.Parse
将客户端提交的参数解析到对象中,然后通过req.Remark == nil
判断客户端是否有提交remark
参数。LIN PENG
谢谢大佬指点!
ayamzh
请教下 文档上例子都是 json的,如果我用http协议 数据用protobuf格式的话,如何写api.func啊。是用
eric chen
观点:参数优先级的出现是因为彻底放弃掉 http method 后引入,
此外,对http method的放弃,对restful的支持上是否也因此有问题呢?
郭强 能讲两句这块的考量吗?
郭强
其实文档里面也提到了为什么会有参数优先级的设计。是为了解决,当不同的提交方式中存在同名的参数名称的场景。
此外,参数并不是按照
http method
进行获取的,参数主要有5种提交方式,文档也有提及到。Jary
这个怎么获取前端传的Content-Type是text/plain的数据?
何安胜
直接用r.Get就可以获取
郭强
你也可以直接使用
r.GetBody
获取客户端的原始提交内容。krugle
发现两个问题,
海亮
第一个问题,这样判断是不靠谱的。
具体参考https://github.com/golang/go/issues/28940
第二个问题,列举一下代码和触发条件?例如谁设置cookie?谁报错?报了什么错?
udtech
请问 HTTP 服务是否支持http/2协议,如果支持是自适应http/1.x 和http/2 吗?
FireTiger
大神们请教一下我这个问题是出在哪里?
入参如下:
{ip: "192.168.0.134", enable: true}
结构体定义
糖水不加糖
结构体首字母大写.你这学go基础学的也太随意了吧.
FireTiger
还真是。。。
王崇宇
感谢框架工作者的付出,这里提一个小的问题,ghttp Request这个结构体的私有属性在一些业务中也有使用场景,比如某些场景下通信验证签名是需要入参排序后做加密,也就是paramMap,queryMap这些集合所有参数集。目前只能通过反射来获取这些内容,框架本身没有暴露访问整个map的api。如果这个是一个普适场景的话,作者有没有考虑增加可以获取这些私有属性的api呢,这样参数处理会更灵活。
郭强
可以提个
issue
记录一下,目前可以通过自定义的Param
参数来做覆盖,不修改原有的Query/Form
参数。王崇宇
写了一个简单的函数来导出参数所有的map集合,已提交了pr,#1840,希望可以做出贡献
tongyonghua
中间件里面调用
r.GetMap(), 接口里面也会调用,看线上日志偶尔会出现以下报错。有大佬知道怎么解决吗 gf版本2.0.6
Stack:
1. ReadAll from body failed
1). github.com/gogf/gf/v2/net/ghttp.(*Request).GetBody
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/net/ghttp/ghttp_request_param.go:157
2). github.com/gogf/gf/v2/net/ghttp.(*Request).parseBody
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/net/ghttp/ghttp_request_param.go:220
3). github.com/gogf/gf/v2/net/ghttp.(*Request).parseForm
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/net/ghttp/ghttp_request_param.go:315
4). github.com/gogf/gf/v2/net/ghttp.(*Request).GetRequestMap
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/net/ghttp/ghttp_request_param_request.go:64
5). github.com/gogf/gf/v2/net/ghttp.(*Request).GetMap
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/net/ghttp/ghttp_request_param.go:179
6). go-sdk/app/system/mobile/internal/middleware.H5ClientSign
/var/www/go/wh-go-sdk/app/system/mobile/internal/middleware/clientSign.go:60
7). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1.1
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/net/ghttp/ghttp_request_middleware.go:54
8). github.com/gogf/gf/v2/net/ghttp.niceCallFunc
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/net/ghttp/ghttp_func.go:56
9). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/net/ghttp/ghttp_request_middleware.go:53
10). github.com/gogf/gf/v2/util/gutil.TryCatch
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/util/gutil/gutil.go:55
11). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/net/ghttp/ghttp_request_middleware.go:48
12). go-sdk/app/utility/response.ReturnResponse
/var/www/go/wh-go-sdk/app/utility/response/response.go:81
13). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1.1
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/net/ghttp/ghttp_request_middleware.go:54
14). github.com/gogf/gf/v2/net/ghttp.niceCallFunc
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/net/ghttp/ghttp_func.go:56
15). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/net/ghttp/ghttp_request_middleware.go:53
16). github.com/gogf/gf/v2/util/gutil.TryCatch
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/util/gutil/gutil.go:55
17). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/net/ghttp/ghttp_request_middleware.go:48
18). go-sdk/app/system/mobile/internal/middleware.CORS
/var/www/go/wh-go-sdk/app/system/mobile/internal/middleware/cors.go:18
19). github.com/gogf/gf/v2/net/ghttp.(*middleware).Next.func1.1
/home/hks/go/pkg/mod/github.com/gogf/gf/v2@v2.0.6/net/ghttp/ghttp_request_middleware.go:54
20). github.com/gogf/gf/v2/net/ghttp.niceCallFunc