• Gin源码之gin.Context结构体及其方法


    Gin源码之gin.Context结构体及其方法

    1.Context结构体

    gin.Context

    // Context is the most important part of gin. It allows us to pass variables between middleware,
    // manage the flow, validate the JSON of a request and render a JSON response for example.
    type Context struct {
    	writermem responseWriter
    	Request   *http.Request
    	Writer    ResponseWriter
    
    	Params   Params
    	handlers HandlersChain
    	index    int8
    	fullPath string
    
    	engine       *Engine
    	params       *Params
    	skippedNodes *[]skippedNode
    
    	// This mutex protect Keys map
    	mu sync.RWMutex
    
    	// Keys is a key/value pair exclusively for the context of each request.
    	Keys map[string]interface{}
    
    	// Errors is a list of errors attached to all the handlers/middlewares who used this context.
    	Errors errorMsgs
    
    	// Accepted defines a list of manually accepted formats for content negotiation.
    	Accepted []string
    
    	// queryCache use url.ParseQuery cached the param query result from c.Request.URL.Query()
    	queryCache url.Values
    
    	// formCache use url.ParseQuery cached PostForm contains the parsed form data from POST, PATCH,
    	// or PUT body parameters.
    	formCache url.Values
    
    	// SameSite allows a server to define a cookie attribute making it impossible for
    	// the browser to send this cookie along with cross-site requests.
    	sameSite http.SameSite
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    2.String方法

    // String writes the given string into the response body.
    func (c *Context) String(code int, format string, values ...interface{}) {
    	c.Render(code, render.String{Format: format, Data: values})
    }
    
    • 1
    • 2
    • 3
    • 4

    3.JSON方法

    code是http响应的状态码,比如写200; H是gin中定义的一个类型(type H map[string]interface{}),可以把H理解成一个json格式的

    // JSON serializes the given struct as JSON into the response body.
    // It also sets the Content-Type as "application/json".
    func (c *Context) JSON(code int, obj interface{}) {
    	c.Render(code, render.JSON{Data: obj})
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    4.Next方法

    // Next should be used only inside middleware.
    // It executes the pending handlers in the chain inside the calling handler.
    // See example in GitHub.
    func (c *Context) Next() {
    	c.index++
    	for c.index < int8(len(c.handlers)) {
    		c.handlers[c.index](c)
    		c.index++
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    5.Aborted方法

    // Abort prevents pending handlers from being called. Note that this will not stop the current handler.
    // Let's say you have an authorization middleware that validates that the current request is authorized.
    // If the authorization fails (ex: the password does not match), call Abort to ensure the remaining handlers
    // for this request are not called.
    func (c *Context) Abort() {
    	c.index = abortIndex
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    6.Set方法

    // Set is used to store a new key/value pair exclusively for this context.
    // It also lazy initializes  c.Keys if it was not used previously.
    func (c *Context) Set(key string, value interface{}) {
    	c.mu.Lock()
    	if c.Keys == nil {
    		c.Keys = make(map[string]interface{})
    	}
    
    	c.Keys[key] = value
    	c.mu.Unlock()
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    7.Get方法

    // Get returns the value for the given key, ie: (value, true).
    // If the value does not exists it returns (nil, false)
    func (c *Context) Get(key string) (value interface{}, exists bool) {
    	c.mu.RLock()
    	value, exists = c.Keys[key]
    	c.mu.RUnlock()
    	return
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    8.MustGet方法

    // MustGet returns the value for the given key if it exists, otherwise it panics.
    func (c *Context) MustGet(key string) interface{} {
    	if value, exists := c.Get(key); exists {
    		return value
    	}
    	panic("Key \"" + key + "\" does not exist")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    9.Query方法

    // Query returns the keyed url query value if it exists,
    // otherwise it returns an empty string `("")`.
    // It is shortcut for `c.Request.URL.Query().Get(key)`
    //     GET /path?id=1234&name=Manu&value=
    // 	   c.Query("id") == "1234"
    // 	   c.Query("name") == "Manu"
    // 	   c.Query("value") == ""
    // 	   c.Query("wtf") == ""
    func (c *Context) Query(key string) string {
    	value, _ := c.GetQuery(key)
    	return value
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    10.DefaultQuery方法

    // DefaultQuery returns the keyed url query value if it exists,
    // otherwise it returns the specified defaultValue string.
    // See: Query() and GetQuery() for further information.
    //     GET /?name=Manu&lastname=
    //     c.DefaultQuery("name", "unknown") == "Manu"
    //     c.DefaultQuery("id", "none") == "none"
    //     c.DefaultQuery("lastname", "none") == ""
    func (c *Context) DefaultQuery(key, defaultValue string) string {
    	if value, ok := c.GetQuery(key); ok {
    		return value
    	}
    	return defaultValue
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    11.GetQuery方法

    // GetQuery is like Query(), it returns the keyed url query value
    // if it exists `(value, true)` (even when the value is an empty string),
    // otherwise it returns `("", false)`.
    // It is shortcut for `c.Request.URL.Query().Get(key)`
    //     GET /?name=Manu&lastname=
    //     ("Manu", true) == c.GetQuery("name")
    //     ("", false) == c.GetQuery("id")
    //     ("", true) == c.GetQuery("lastname")
    func (c *Context) GetQuery(key string) (string, bool) {
    	if values, ok := c.GetQueryArray(key); ok {
    		return values[0], ok
    	}
    	return "", false
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    12.HTML方法

    // HTML renders the HTTP template specified by its file name.
    // It also updates the HTTP code and sets the Content-Type as "text/html".
    // See http://golang.org/doc/articles/wiki/
    func (c *Context) HTML(code int, name string, obj interface{}) {
    	instance := c.engine.HTMLRender.Instance(name, obj)
    	c.Render(code, instance)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    13.PostForm方法

    // PostForm returns the specified key from a POST urlencoded form or multipart form
    // when it exists, otherwise it returns an empty string `("")`.
    func (c *Context) PostForm(key string) string {
    	value, _ := c.GetPostForm(key)
    	return value
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    14.DefaultPostForm方法

    // DefaultPostForm returns the specified key from a POST urlencoded form or multipart form
    // when it exists, otherwise it returns the specified defaultValue string.
    // See: PostForm() and GetPostForm() for further information.
    func (c *Context) DefaultPostForm(key, defaultValue string) string {
    	if value, ok := c.GetPostForm(key); ok {
    		return value
    	}
    	return defaultValue
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    15.PostFormMap方法

    // PostFormMap returns a map for a given form key.
    func (c *Context) PostFormMap(key string) map[string]string {
    	dicts, _ := c.GetPostFormMap(key)
    	return dicts
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    16.GetPostForm方法

    // GetPostForm is like PostForm(key). It returns the specified key from a POST urlencoded
    // form or multipart form when it exists `(value, true)` (even when the value is an empty string),
    // otherwise it returns ("", false).
    // For example, during a PATCH request to update the user's email:
    //     email=mail@example.com  -->  ("mail@example.com", true) := GetPostForm("email") // set email to "mail@example.com"
    // 	   email=                  -->  ("", true) := GetPostForm("email") // set email to ""
    //                             -->  ("", false) := GetPostForm("email") // do nothing with email
    func (c *Context) GetPostForm(key string) (string, bool) {
    	if values, ok := c.GetPostFormArray(key); ok {
    		return values[0], ok
    	}
    	return "", false
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    17.MustBindWith

    Gin 提供了两类绑定方法:MustBindWith和 Should bind。
    MustBindWith的方法有 Bind,BindJSON,BindXML,BindQuery,BindYAML,这些方法属于 MustBindWith的具体调用。
    Must bind 如果发生绑定错误,则请求终止,并触发 c.AbortWithError(400, err).SetType(ErrorTypeBind)。响应状态码被设置为 400 并且 Content-Type 被设置为 text/plain; charset=utf-8。如果您在此之后尝试设置响应状态码,Gin会输出日志 [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422。

    Should bind的方法有 ShouldBind,ShouldBindJSON,ShouldBindXML,ShouldBindQuery,ShouldBindYAML,这些方法属于 ShouldBindWith 的具体调用。
    Should bind 如果发生绑定错误,Gin 会返回错误并由开发者处理错误和请求。

    // MustBindWith binds the passed struct pointer using the specified binding engine.
    // It will abort the request with HTTP 400 if any error occurs.
    // See the binding package.
    func (c *Context) MustBindWith(obj interface{}, b binding.Binding) error {
    	if err := c.ShouldBindWith(obj, b); err != nil {
    		c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
    		return err
    	}
    	return nil
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    18.BindWith方法

    根据自己指定的Content-Type来进行解析.
    ShouldBindWith和BindWith区别就是BindWith会在head中添加400的返回信息(如果解析错误的话,在header中写一个400的状态码),而ShouldBindWith不会(解析错误直接返回,至于要给客户端返回什么错误状态码有你决定)

    // BindWith binds the passed struct pointer using the specified binding engine.
    // See the binding package.
    func (c *Context) BindWith(obj interface{}, b binding.Binding) error {
    	log.Println(`BindWith(\"interface{}, binding.Binding\") error is going to
    	be deprecated, please check issue #662 and either use MustBindWith() if you
    	want HTTP 400 to be automatically returned if any error occur, or use
    	ShouldBindWith() if you need to manage the error.`)
    	return c.MustBindWith(obj, b)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    19.Bind方法

    方法内部会自动识别请求中是哪种Content-Type,并以这种方式来去解析
    ShouldBind和Bind区别就是Bind会在head中添加400的返回信息(如果解析错误的话,在header中写一个400的状态码),而ShouldBind不会(解析错误直接返回,至于要给客户端返回什么错误状态码有你决定)

    // Bind checks the Content-Type to select a binding engine automatically,
    // Depending the "Content-Type" header different bindings are used:
    //     "application/json" --> JSON binding
    //     "application/xml"  --> XML binding
    // otherwise --> returns an error.
    // It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
    // It decodes the json payload into the struct specified as a pointer.
    // It writes a 400 error and sets Content-Type header "text/plain" in the response if input is not valid.
    func (c *Context) Bind(obj interface{}) error {
    	b := binding.Default(c.Request.Method, c.ContentType())
    	return c.MustBindWith(obj, b)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    20.BindJSON方法

    方法会以JSON这种Content-Type这种方式来去去解析
    ShouldBindJSON和BindJSON区别就是Bind会在head中添加400的返回信息(如果解析错误的话,在header中写一个400的状态码),而ShouldBindJSON不会(解析错误直接返回,至于要给客户端返回什么错误状态码有你决定)

    // BindJSON is a shortcut for c.MustBindWith(obj, binding.JSON).
    func (c *Context) BindJSON(obj interface{}) error {
    	return c.MustBindWith(obj, binding.JSON)
    }
    
    • 1
    • 2
    • 3
    • 4

    21.BindXML方法

    // BindXML is a shortcut for c.MustBindWith(obj, binding.BindXML).
    func (c *Context) BindXML(obj interface{}) error {
    	return c.MustBindWith(obj, binding.XML)
    }
    
    • 1
    • 2
    • 3
    • 4

    22.BindQuery方法

    // BindQuery is a shortcut for c.MustBindWith(obj, binding.Query).
    func (c *Context) BindQuery(obj interface{}) error {
    	return c.MustBindWith(obj, binding.Query)
    }
    
    • 1
    • 2
    • 3
    • 4

    23.BindYAML方法

    // BindYAML is a shortcut for c.MustBindWith(obj, binding.YAML).
    func (c *Context) BindYAML(obj interface{}) error {
    	return c.MustBindWith(obj, binding.YAML)
    }
    
    • 1
    • 2
    • 3
    • 4

    24.BindHeader方法

    // BindHeader is a shortcut for c.MustBindWith(obj, binding.Header).
    func (c *Context) BindHeader(obj interface{}) error {
    	return c.MustBindWith(obj, binding.Header)
    }
    
    • 1
    • 2
    • 3
    • 4

    25.BindUri方法

    // BindUri binds the passed struct pointer using binding.Uri.
    // It will abort the request with HTTP 400 if any error occurs.
    func (c *Context) BindUri(obj interface{}) error {
    	if err := c.ShouldBindUri(obj); err != nil {
    		c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind) // nolint: errcheck
    		return err
    	}
    	return nil
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    26.ShouldBindWith方法

    // ShouldBindWith binds the passed struct pointer using the specified binding engine.
    // See the binding package.
    func (c *Context) ShouldBindWith(obj interface{}, b binding.Binding) error {
    	return b.Bind(c.Request, obj)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    27.ShouldBind方法

    为了能够更方便的获取请求相关参数,提高开发效率,我们可以基于请求的Content-Type识别请求数据类型并利用反射机制自动提取请求中QueryString、form表单、JSON、XML等参数到结构体中。ShouldBind()能够基于请求自动提取JSON、form表单和QueryString类型的数据,并把值绑定到指定的结构体对象。

    ShouldBind会按照下面的顺序解析请求中的数据完成绑定:
    如果是 GET 请求,只使用 “form” tag 绑定query引擎。
    如果是 POST 请求,首先检查 content-type 是否为 JSON 或 XML,然后再使用 Form(form-data)。

    // ShouldBind checks the Content-Type to select a binding engine automatically,
    // Depending the "Content-Type" header different bindings are used:
    //     "application/json" --> JSON binding
    //     "application/xml"  --> XML binding
    // otherwise --> returns an error
    // It parses the request's body as JSON if Content-Type == "application/json" using JSON or XML as a JSON input.
    // It decodes the json payload into the struct specified as a pointer.
    // Like c.Bind() but this method does not set the response status code to 400 and abort if the json is not valid.
    func (c *Context) ShouldBind(obj interface{}) error {
    	b := binding.Default(c.Request.Method, c.ContentType())
    	return c.ShouldBindWith(obj, b)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    28.ShouldBindJSON方法

    // ShouldBindJSON is a shortcut for c.ShouldBindWith(obj, binding.JSON).
    func (c *Context) ShouldBindJSON(obj interface{}) error {
    	return c.ShouldBindWith(obj, binding.JSON)
    }
    
    • 1
    • 2
    • 3
    • 4

    29.ShouldBindXML方法

    // ShouldBindXML is a shortcut for c.ShouldBindWith(obj, binding.XML).
    func (c *Context) ShouldBindXML(obj interface{}) error {
    	return c.ShouldBindWith(obj, binding.XML)
    }
    
    • 1
    • 2
    • 3
    • 4

    30.ShouldBindQuery方法

    ShouldBindQuery 如果 url 查询参数和 post 数据都存在,函数只绑定 url 查询参数而忽略 post 数据。

    // ShouldBindQuery is a shortcut for c.ShouldBindWith(obj, binding.Query).
    func (c *Context) ShouldBindQuery(obj interface{}) error {
    	return c.ShouldBindWith(obj, binding.Query)
    }
    
    • 1
    • 2
    • 3
    • 4

    31. ShouldBindYAML方法

    // ShouldBindYAML is a shortcut for c.ShouldBindWith(obj, binding.YAML).
    func (c *Context) ShouldBindYAML(obj interface{}) error {
    	return c.ShouldBindWith(obj, binding.YAML)
    }
    
    • 1
    • 2
    • 3
    • 4

    32.ShouldBindHeader方法

    // ShouldBindHeader is a shortcut for c.ShouldBindWith(obj, binding.Header).
    func (c *Context) ShouldBindHeader(obj interface{}) error {
    	return c.ShouldBindWith(obj, binding.Header)
    }
    
    • 1
    • 2
    • 3
    • 4

    33.ShouldBindUri方法

    // ShouldBindUri binds the passed struct pointer using the specified binding engine.
    func (c *Context) ShouldBindUri(obj interface{}) error {
    	m := make(map[string][]string)
    	for _, v := range c.Params {
    		m[v.Key] = []string{v.Value}
    	}
    	return binding.Uri.BindUri(m, obj)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    34.QueryMap方法

    // QueryMap returns a map for a given query key.
    func (c *Context) QueryMap(key string) map[string]string {
    	dicts, _ := c.GetQueryMap(key)
    	return dicts
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 相关阅读:
    109.firefly-extboot的生成脚本
    Flink-cdc 同步mysql数据
    基于php柚子商城
    IDEA的初步使用
    采购实用技巧,5个瓶颈物料的采购方法
    【clickhouse专栏】数据库、数据仓库之间的区别与联系
    消息队列——引入的问题:重复消费&顺序消费&分布式事务
    解决微信小程序回调地狱问题
    java 实现串口通讯
    【python基础3】
  • 原文地址:https://blog.csdn.net/qq_53267860/article/details/126675572