请求上下文
请求上下文 RequestContext 是用于保存 HTTP 请求和设置 HTTP 响应的上下文,它提供了许多方便的 API 接口帮助用户开发。
Hertz 在 HandlerFunc 设计上,同时提供了一个标准 context.Context 和一个 RequestContext 作为函数的入参。 handler/middleware 函数签名为:
type HandlerFunc func(c context.Context, ctx *RequestContext)
context.Context 与 RequestContext 都有存储值的能力,具体选择使用哪一个上下文有个简单依据:所储存值的生命周期和所选择的上下文要匹配。
ctx 主要用来存储请求级别的变量,请求结束就回收了,特点是查询效率高(底层是 map),协程不安全,且未实现 context.Context 接口。
c 作为上下文在中间件 /handler 之间传递,协程安全。所有需要 context.Context 接口作为入参的地方,直接传递 c 即可。
请求
URI
func (ctx *RequestContext) Host() []byte func (ctx *RequestContext) FullPath() string func (ctx *RequestContext) SetFullPath(p string) func (ctx *RequestContext) Path() []byte func (ctx *RequestContext) Param(key string) string func (ctx *RequestContext) Query(key string) string func (ctx *RequestContext) DefaultQuery(key, defaultValue string) string func (ctx *RequestContext) GetQuery(key string) (string, bool) func (ctx *RequestContext) QueryArgs() *protocol.Args func (ctx *RequestContext) URI() *protocol.URI
Host
获取请求的主机地址。
函数签名:
func (ctx *RequestContext) Host() []byte
示例:
// GET http://example.com h.GET("/", func(c context.Context, ctx *app.RequestContext) { host := ctx.Host() // host == []byte("example.com") })
FullPath
获取匹配的路由完整路径,对于未匹配的路由返回空字符串。
函数签名:
func (ctx *RequestContext) FullPath() string
示例:
h := server.Default(server.WithHandleMethodNotAllowed(true)) // GET http://example.com/user/bar h.GET("/user/:name", func(c context.Context, ctx *app.RequestContext) { fpath := ctx.FullPath() // fpath == "/user/:name" }) // GET http://example.com/bar h.NoRoute(func(c context.Context, ctx *app.RequestContext) { fpath := ctx.FullPath() // fpath == "" }) // POST http://example.com/user/bar h.NoMethod(func(c context.Context, ctx *app.RequestContext) { fpath := ctx.FullPath() // fpath == "" })
SetFullPath
设置 FullPath 的值。
注意:FullPath 由路由查找时分配,通常你不需要使用 SetFullPath 去覆盖它。
函数签名:
func (ctx *RequestContext) SetFullPath(p string)
示例:
h.GET("/user/:name", func(c context.Context, ctx *app.RequestContext) { ctx.SetFullPath("/v1/user/:name") fpath := ctx.FullPath() // fpath == "/v1/user/:name" })
Path
获取请求的路径。
注意:出现参数路由时 Path 给出命名参数匹配后的路径,而 FullPath 给出原始路径。
函数签名:
func (ctx *RequestContext) Path() []byte
示例:
// GET http://example.com/user/bar h.GET("/user/:name", func(c context.Context, ctx *app.RequestContext) { path := ctx.Path() // path == []byte("/user/bar") })
Param
获取路由参数的值。
函数签名:
func (ctx *RequestContext) Param(key string) string
示例:
// GET http://example.com/user/bar h.GET("/user/:name", func(c context.Context, ctx *app.RequestContext) { name := ctx.Param("name") // name == "bar" id := ctx.Param("id") // id == "" })
Query
获取路由 Query String 参数中指定属性的值,如果没有返回空字符串。
函数签名:
func (ctx *RequestContext) Query(key string) string
示例:
// GET http://example.com/user?name=bar h.GET("/user", func(c context.Context, ctx *app.RequestContext) { name := ctx.Query("name") // name == "bar" id := ctx.Query("id") // id == "" })
DefaultQuery
获取路由 Query String 参数中指定属性的值,如果没有返回设置的默认值。
函数签名:
func (ctx *RequestContext) DefaultQuery(key, defaultValue string) string
示例:
// GET http://example.com/user?name=bar&&age= h.GET("/user", func(c context.Context, ctx *app.RequestContext) { name := ctx.DefaultQuery("name", "tom") // name == "bar" id := ctx.DefaultQuery("id", "123") // id == "123" age := ctx.DefaultQuery("age", "45") // age == "" })
GetQuery
获取路由 Query String 参数中指定属性的值以及属性是否存在。
函数签名:
func (ctx *RequestContext) GetQuery(key string) (string, bool)
示例:
// GET http://example.com/user?name=bar&&age= h.GET("/user", func(c context.Context, ctx *app.RequestContext) { name, hasName := ctx.GetQuery("name") // name == "bar", hasName == true id, hasId := ctx.GetQuery("id") // id == "", hasId == false age, hasAge := ctx.GetQuery("age") // age == "", hasAge == true })
QueryArgs
获取路由 Query String 参数对象。
函数签名:
func (ctx *RequestContext) QueryArgs() *protocol.Args
Args 对象
Args 对象提供了以下方法获取/设置 Query String 参数。
函数签名 | 说明 |
func (a *Args) Set(key, value string) | 设置 Args 对象 key 的值 |
func (a *Args) Reset() | 重置 Args 对象 |
func (a *Args) CopyTo(dst *Args) | 将 Args 对象拷贝到 dst |
func (a *Args) Del(key string) | 删除 Args 对象 key 的键值对 |
func (a *Args) DelBytes(key []byte) | 删除 Args 对象字节数组类型 key 的键值对 |
func (a *Args) Has(key string) bool | 获取 Args 对象是否存在 key 的键值对 |
func (a *Args) String() string | 将 Args 对象转换为字符串类型的 Query String |
func (a *Args) QueryString() []byte | 将 Args 对象转换为字节数组类型的 Query String |
func (a *Args) ParseBytes(b []byte) | 解析字节数组并将键值对存入 Args 对象 |
func (a *Args) Peek(key string) []byte | 获取 Args 对象 key 的值 |
func (a *Args) PeekExists(key string) (string, bool) | 获取 Args 对象 key 的值以及是否存在 |
func (a *Args) Len() int | 获取 Args 对象键值对数量 |
func (a *Args) AppendBytes(dst []byte) []byte | 将 Args 对象 Query String 附加到 dst 中并返回 |
func (a *Args) VisitAll(f func(key, value []byte)) | 遍历 Args 对象所有的键值对 |
func (a *Args) WriteTo(w io.Writer) (int64, error) | 将 Args 对象 Query String 写入 io.Writer 中 |
func (a *Args) Add(key, value string) | 添加 Args 对象键为 key 的值 |
示例: |
// GET http://example.com/user?name=bar&&age=&&pets=dog&&pets=cat h.GET("/user", func(c context.Context, ctx *app.RequestContext) { args := ctx.QueryArgs() // get information from args s := args.String() // s == "name=bar&age=&pets=dog&pets=cat" qs := args.QueryString() // qs == []byte("name=bar&age=&pets=dog&pets=cat") cpqs := args.AppendBytes([]byte(nil)) // cpqs == []byte("name=bar&age=&pets=dog&pets=cat") name := args.Peek("name") // name == []byte("bar") hasName := args.Has("name") // hasName == true age, hasAge := args.PeekExists("age") // age == "", hasAge == true len := args.Len() // len == 4 args.VisitAll(func(key, value []byte) { // 1. key == []byte("name"), value == []byte("bar") // 2. key == []byte("age"), value == nil // 3. key == []byte("pets"), value == []byte("dog") // 4. key == []byte("pets"), value == []byte("cat") }) // send information to io.Writer req := protocol.AcquireRequest() n, err := args.WriteTo(req.BodyWriter()) // n == 31 err == nil s := req.BodyBuffer().String() // s == "name=bar&age=&pets=dog&pets=cat" // change args var newArgs protocol.Args args.CopyTo(&newArgs) newArgs.Set("version", "v1") version := newArgs.Peek("version") //version == []byte("v1") newArgs.Del("age") hasAgeAfterDel := newArgs.Has("age") // hasAgeAfterDel == false newArgs.DelBytes([]byte("name")) hasNameAfterDel := newArgs.Has("name") // hasNameAfterDel == false newArgs.Add("name", "foo") newName := newArgs.Peek("name") //newName == []byte("foo") newArgs.Reset() empty := newArgs.String() // empty == "" // parse args var newArgs2 protocol.Args newArgs2.ParseBytes([]byte("name=bar&age=20")) nqs2 := newArgs2.String() // nqs2 == "name=bar&age=20" })
URI
返回请求的 URI 对象。
函数签名:
func (ctx *RequestContext) URI() *protocol.URI
URI 对象提供了以下方法获取/设置 URI。
函数签名 | 说明 |
func (u *URI) CopyTo(dst *URI) | 拷贝 URI 对象的副本到 dst |
func (u *URI) QueryArgs() | *Args 获取 Args 对象 |
func (u *URI) Hash() []byte | 获取 Hash 值,比如 http://example.com/user?baz=123#qwe 的 Hash 是 qwe |
func (u *URI) SetHash(hash string) | 设置 Hash |
func (u *URI) SetHashBytes(hash []byte) | 设置 []byte 类型 Hash |
func (u *URI) Username() []byte | 获取 Username |
func (u *URI) SetUsername(username string) | 设置 Username |
func (u *URI) SetUsernameBytes(username []byte) | 设置 []byte 类型 Username |
func (u *URI) Password() []byte | 获取 Password |
func (u *URI) SetPassword(password string) | 设置 Password |
func (u *URI) SetPasswordBytes(password []byte) | 设置 []byte 类型 Password |
func (u *URI) QueryString() []byte | 获取 Query String,比如 http://example.com/user?baz=123 的 Query String 是 baz=123 |
func (u *URI) SetQueryString(queryString string) | 设置 Query String |
func (u *URI) SetQueryStringBytes(queryString []byte) | 设置 []byte 类型的 Query String |
func (u *URI) Path() []byte | 获取 Path,比如 http://example.com/user/he%20rtz 的 Path 是 /user/he rtz |
func (u *URI) PathOriginal() []byte | 获取未转义的 Path,比如 http://example.com/user/he%20rtz 的 Path 是 /user/he%20rtz |
func (u *URI) SetPath(path string) | 设置 Path |
func (u *URI) SetPathBytes(path []byte) | 设置 []byte 类型 Path |
func (u *URI) String() string | 获取完整 URI 比如 http://example.com/user?baz=123 的完整 URI 是 http://example.com/user?baz=123 |
func (u *URI) FullURI() []byte | 获取 []byte 类型的完整 URI |
func (u *URI) Scheme() []byte | 获取协议,如 http |
func (u *URI) SetScheme(scheme string) | 设置协议 |
func (u *URI) SetSchemeBytes(scheme []byte) | 设置 []byte 类型的协议 |
func (u *URI) Host() []byte | 获取 Host,比如 http://example.com/user 的 Host 是 example.com |
func (u *URI) SetHost(host string) | 设置 Host |
func (u *URI) SetHostBytes(host []byte) | 设置 []byte 类型 Host |
func (u *URI) LastPathSegment() []byte | 获取 Path 的最后一部分,比如 Path /foo/bar/baz.html 的最后一部分是 baz.html |
func (u *URI) Update(newURI string) | 更新 URI |
func (u *URI) UpdateBytes(newURI []byte) | 更新 []byte 类型的 URI |
func (u *URI) Parse(host, uri []byte) | 初始化 URI |
func (u *URI) AppendBytes(dst []byte) []byte | 将完整的 URI 赋值到 dst 中并返回 dst |
func (u *URI) RequestURI() []byte | 获取 RequestURI,比如 http://example.com/user?baz=123 的 RequestURI 是 /user?baz=123 |
func (u *URI) Reset() | 重置 URI |
字节赫兹 框架教程 一请求上下文之请求(二)https://developer.aliyun.com/article/1391803