请求输入依靠 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 StringBody 参数解析。
GetForm获取表单方式传递过来的参数,表单方式提交的参数 Content-Type 往往为 application/x-www-form-urlencoded, application/form-data, multipart/form-data, multipart/mixed 等等。
GetRequest获取客户端提交的所有参数,按照参数优先级进行覆盖,不区分提交方式。
GetStruct将指定提交类型的所有请求参数绑定到指定的 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路由参数。来源于路由规则匹配。
QueryQuery 参数。 URL 中的 Query String 参数解析,如: http://127.0.0.1/index?id=1&name=john 中的 id=1&name=john
Form表单参数。最常见的提交方式,提交的 Content-Type 往往为: application/x-www-form-urlencodedmultipart/form-datamultipart/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() 将会分别返回 float32float64 类型的数值 19.66。但是, Get(xxx).Int()/ Get(xxx).Uint() 将会返回 19(如果参数为 float 类型的字符串,将会按照 向下取整 进行整型转换)。

请求输入🔥 - 图1提示

聪明的您一定发现了,获取到的参数都是 泛型变量,根据该泛型变量再根据需要调用对应的方法转换为对应的数据类型。

使用示例:

  1. package main
  2. import (
  3. "github.com/gogf/gf/v2/frame/g"
  4. "github.com/gogf/gf/v2/net/ghttp"
  5. )
  6. func main() {
  7. s := g.Server()
  8. s.BindHandler("/", func(r *ghttp.Request) {
  9. r.Response.Writeln(r.Get("amount").String())
  10. r.Response.Writeln(r.Get("amount").Int())
  11. r.Response.Writeln(r.Get("amount").Float32())
  12. })
  13. s.SetPort(8199)
  14. s.Run()
  15. }

执行后我们访问地址 http://127.0.0.1:8199/?amount=19.66 页面输出

  1. 19.66
  2. 19
  3. 19.66

参数优先级

我们考虑一种场景,当不同的提交方式中存在同名的参数名称会怎么样?在 GoFrame 框架下,我们根据不同的获取方法,将会按照不同的优先级进行获取,优先级高的方式提交的参数将会优先覆盖其他方式的同名参数。优先级规则如下:

  1. GetGetRequset 方法: Router < Query < Body < Form < Custom,也就是说自定义参数的优先级最高,其次是 Form 表单参数,再次是 Body 提交参数,以此类推。例如, QueryForm 中都提交了同样名称的参数 id,参数值分别为 12,那么 Get("id")/ GetForm("id") 将会返回 2,而 GetQuery("id") 将会返回 1
  2. GetQuery 方法: Query > Body,也就是说 query string 的参数将会覆盖 Body 中提交的同名参数。例如, QueryBody 中都提交了同样名称的参数 id,参数值分别为 12,那么 Get("id") 将会返回 2,而 GetQuery("id") 将会返回 1
  3. GetForm 方法:由于该类型的方法仅用于获取 Form 表单参数,因此没什么优先级的差别。

使用示例:

  1. package main
  2. import (
  3. "github.com/gogf/gf/v2/frame/g"
  4. "github.com/gogf/gf/v2/net/ghttp"
  5. )
  6. func main() {
  7. s := g.Server()
  8. s.BindHandler("/input", func(r *ghttp.Request) {
  9. r.Response.Writeln(r.Get("amount"))
  10. })
  11. s.BindHandler("/query", func(r *ghttp.Request) {
  12. r.Response.Writeln(r.GetQuery("amount"))
  13. })
  14. s.SetPort(8199)
  15. s.Run()
  16. }

执行后,我们通过 curl 工具进行测试:

  1. $ curl -d "amount=1" -X POST "http://127.0.0.1:8199/input?amount=100"
  2. 1
  3. $ curl -d "amount=1" -X POST "http://127.0.0.1:8199/query?amount=100"
  4. 100

可以看到,当我们访问 /input 路由时,该路由方法中采用了 Get 方法获取 amount 参数,按照同名优先级的规则返回了 1,即 body 中传递的参数。而当我们通过 /query 路由访问时,该路由方法内部使用了 GetQuery 方法获取 amount 参数,因此获取到的是 query string 参数中的 amount 值,返回了 100

大小写敏感

需要注意哦, 参数名称是大小写敏感 的哦,例如客户端提交的参数 nameName 是两个参数。 由于服务端默认是通过字符串名称获取参数,因此大小写敏感并不会产生什么问题,但是如果服务端接收的是一个API对象,那么可能需要注意一下。我们来看一个例子。

服务端:

  1. package main
  2. import (
  3. "context"
  4. "github.com/gogf/gf/v2/frame/g"
  5. "github.com/gogf/gf/v2/net/ghttp"
  6. )
  7. type Controller struct{}
  8. type PathReq struct {
  9. g.Meta `path:"/api/v1/*path" method:"post"`
  10. Path string
  11. }
  12. type PathRes struct {
  13. Path string
  14. }
  15. func (c *Controller) Path(ctx context.Context, req *PathReq) (res *PathRes, err error) {
  16. return &PathRes{Path: req.Path}, nil
  17. }
  18. func main() {
  19. s := g.Server()
  20. s.SetPort(8199)
  21. s.Use(ghttp.MiddlewareHandlerResponse)
  22. s.Group("/", func(group *ghttp.RouterGroup) {
  23. group.Bind(&Controller{})
  24. })
  25. s.Run()
  26. }

服务端的接口设计原意是定义一个路由参数 path,并且通过 API 对象的 Path 属性来接收。

客户端:

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/gogf/gf/v2/frame/g"
  5. "github.com/gogf/gf/v2/os/gctx"
  6. )
  7. func main() {
  8. var (
  9. ctx = gctx.New()
  10. client = g.Client()
  11. )
  12. client.SetPrefix("http://127.0.0.1:8199")
  13. for i := 0; i < 10; i++ {
  14. fmt.Println(client.PostContent(ctx, "/api/v1/user/info", `{"Path":"user/profile"}`))
  15. }
  16. }

根据我们的理解,客户端提交后,服务端应该会收到路由参数 path 的值为 user/info。但是很奇怪,由于程序 BUG,客户端提交的 Body 中同样提交了一个 JSON,参数名称为 Path,参数值为 user/profile。那么这个时候服务端 API 对象中的属性 Path 将会是哪个值呢?

我们将客户端反复执行多次,发现输出的结果都是:

  1. {"code":0,"message":"","data":{"Path":"user/profile"}}
  2. {"code":0,"message":"","data":{"Path":"user/profile"}}
  3. {"code":0,"message":"","data":{"Path":"user/profile"}}
  4. {"code":0,"message":"","data":{"Path":"user/profile"}}
  5. {"code":0,"message":"","data":{"Path":"user/profile"}}
  6. {"code":0,"message":"","data":{"Path":"user/profile"}}
  7. {"code":0,"message":"","data":{"Path":"user/profile"}}
  8. {"code":0,"message":"","data":{"Path":"user/profile"}}
  9. {"code":0,"message":"","data":{"Path":"user/profile"}}
  10. {"code":0,"message":"","data":{"Path":"user/profile"}}

即参数都是 Body 中提交的值,而不是路由参数中的值。其实, 由于参数大小写敏感的缘故,服务端这个时候接受到了两个参数,一个是路由参数 path,一个是 Body JSON 提交的 Path。服务端在转换 API 参数对象的时候,由于属性 PathBody JSON 中提交的 Path 更匹配,因此,使用的是 Body JSON 中的 Path 的值。

相关文档

📄️ 请求输入-复杂参数在使用GoFrame框架构建的应用中,通过Query或Form参数实现复杂参数传递。文中详细阐述了同名参数、数组参数及Map参数的提交格式及其在服务端的解析方式,并给出相应的代码示例。建议在遇到复杂参数传递场景时,尽量使用JSON数据编码进行管理和维护。

📄️ 请求输入-对象处理该文档详细介绍了在使用GoFrame框架时如何处理请求输入的对象转换。通过将输入和输出定义为struct结构体对象,便于结构化参数的维护。文中介绍了默认和自定义的参数映射规则,以及如何通过Request对象的Parse方法进行便捷的对象转换和数据校验。

📄️ 请求输入-请求校验在GoFrame框架中通过v标签为结构体属性实现请求的输入校验。在示例中,我们讲解了如何使用gvalid模块进行校验,如何设置和解析注册请求的数据结构,以及在出现校验错误时如何处理,并展示了如何通过curl测试接口响应的数据和错误信息。此外,我们提供了不同版本的使用建议,以提高用户体验和代码的易用性。

📄️ 请求输入-JSON/XMLGoFrame框架对JSON和XML数据格式的原生支持,详细描述了如何通过GoFrame框架的Request对象来处理客户端提交的数据格式,提高开发效率。文档中包括示例代码演示如何解析和验证提交的数据,以及如何进行数据格式转换,为开发者提供了便捷的数据获取和处理能力。

📄️ 请求输入-默认值绑定在GoFrame框架中使用struct tag为请求输入对象的属性绑定默认值的功能。通过示例展示了如何定义参数对象并为其属性设置默认值,以及如何在服务端处理和验证请求参数。特别强调了在未提交参数时,默认值将生效,而在提交了参数(即使为空)的情况下,默认值将被忽略。同时提供了一些关于默认值参数绑定的注意事项建议。

📄️ 请求输入-自定义参数在GoFrame框架中设置和获取自定义请求参数。自定义变量具有最高优先级,可覆盖客户端提交的参数,适用于请求流程中的变量共享。本教程还提供实际代码示例,展示如何在中间件中使用SetParam和GetParam方法来管理请求参数。

📄️ 请求输入-Context在GoFrame框架中使用Context对象处理请求流程中的上下文变量共享。通过提供必要的方法,开发者可以在请求开始时设置自定义变量,并在后续的处理中访问它们。此外,本文包含了如何集成第三方组件以增强功能的示例代码和详细步骤。

📄️ 请求输入-文件上传在GoFrame框架中实现文件上传的基本步骤和方法。借助HTTPClient章节提供的信息,开发者可以深入理解和掌握如何在应用程序中处理文件上传请求,以确保在实际应用中有效地管理文件数据。