编程技术文章分享与教程

网站首页 > 技术文章 正文

Gin源码分析 - Context功能概述 golang context源码

hmc789 2024-11-08 19:43:22 技术文章 2 ℃

1 介绍

从前面的介绍可以了解到整个Gin由Engine、Route、Context等几个主要组成。Context是Gin框架中非常重要的一点,它允许我们在中间件间共享变量,管理整个流程,获取请求参数,渲染结果,通常情况下我们的业务逻辑处理也是在整个Context引用对象中进行实现的。Context的代码在context.go中实现。本文对Context的主要数据结构,主要的提供的方法进行概要的功能性介绍,后续章节则对每一部分进行详细的分析。

2 结构体说明

该Context主要实现了对Request和Response的封装以及一些参数的传递。其数据结构如下:

// 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.
// Context是gin中最重要的部分。它允许我们在中间件中共享变量,管理流程,对请求中的JSON进行有效性检查并且渲染一个JSON的响应。
type Context struct {
    writermem responseWriter // 响应处理
    Request   *http.Request  // 请求信息
    Writer    ResponseWriter // 响应处理接口

    Params   Params          // URL参数
    handlers HandlersChain   // 请求处理列表 
    index    int8            // 用于对中间件进行流程控制
    fullPath string          // http请求的全路径地址

    engine       *Engine     // gin框架的Engine结构体指针
    params       *Params
    skippedNodes *[]skippedNode

    // This mutex protect Keys map
    // 对下面的Keys字段进行写保护的锁
    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()
    // 管理解析后的Query参数
    queryCache url.Values

    // formCache use url.ParseQuery cached PostForm contains the parsed form data from POST, PATCH,
    // or PUT body parameters.
    // 管理解析后的Form参数
    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
}

3 错误处理

  • func(c *Context)Error(err error)*Error,将错误添加到上下文中

4 元数据管理

主要通过Keys map[string]interface{},在各个中间件中共享变量,提供的方法两类,Set和Get方法,只不过Get有很多变种,方便获取某种类型的数据。

函数

功能

Set(key string, value interface{})

给context设置一个新的键值对

Get(key string) (value interface{}, exists bool)

返回指定的key的值,以及是否存在

MustGet(key string) interface{}

返回指定key的值,不存在则panic

GetString(key string) (s string)

返回string类型

GetBool(key string) (b bool)

返回bool类型

GetInt(key string) (i int)

返回int类型

GetStringSlice(key string) (ss []string)

返回一个字符串切片

GetStringMap(key string) (sm map[string]interface{})

返回一个map结构,类型为map[string]interface{}

GetStringMapString(key string) (sms map[string]string)

返回一个map结构,类型为map[string]string

GetStringMapStringSlice(key string) (smss map[string][]string)

返回一个map结构,类型为map[string][]string

5 请求处理

5.1 获取参数

Context的主要功能之一就是对各种Request的参数进行解析和处理,当前Context主要支持URL Param、URL Query、PostForm、FormFile和MultipartForm等几类请求参数的类型,提供的主要方法如下表。

(1)URL Param,例如一个Restful API的定义为/user/:name,实际发送的请求是/user/john, 这个请求中name就是Param参数,参数值就是john

(2)URL Query,例如一个Restful API的定义为/getUserInfo?id=1234&age=18,这个请求中 id,age就是Query参数,参数值是1234,18

(3)PostForm,在POST请求的,请求体中发送的请求参数,例如下面是一个JSON格式的PostForm参数。

POST /post HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 18
Content-Type: application/json
Host: pie.dev
User-Agent: HTTPie/3.1.0

{
    "id": "1234",
    "age": "18"
}

(4)FormFile,在POST请求中,主要用于上传文件,在Form中采用的是multipart/form-data编码方式,在下例子中上传了一个文件,参数为filename,值为py1.cfg,文件内容中也包含中请求体中。

POST /post HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 437
Content-Type: multipart/form-data; boundary=55315202afc745a99261513f37e7ffa2
Host: pie.dev
User-Agent: HTTPie/3.1.0

--55315202afc745a99261513f37e7ffa2
Content-Disposition: form-data; name="filename"; filename="py1.cfg"

home = d:\python\python37
implementation = CPython
version_info = 3.7.6.final.0
virtualenv = 20.0.7
include-system-site-packages = false
base-prefix = d:\python\python37
base-exec-prefix = d:\python\python37
base-executable = d:\python\python37\python.exe
prompt = (python_study)

--55315202afc745a99261513f37e7ffa2--

(5)MultipartForm,在POST请求中,除了上传文件外,还可以存储其它的参数。

函数

功能

Param(key string) string

返回URL的Param参数值,
(1)路由:uri_patten: "/user/:id",
(2)请求:url: "/user/john"
(3)使用:c.Param("id") = "john"

Query(key string) string

返回URL中的Query参数值
(1)路由:/path?id=1234&name=Manu
(2)使用:c.Query("id")=1234,
c.Query("name")=Manu

DefaultQuery(key, defaultValue string) string

返回URL中的查询参数值,但是提供了一个默认值

QueryArray(key string) []string

返回指定key的对应的数组切片

GetQueryArray(key string) ([]string, bool)

同上,会返回状态

QueryMap(key string) map[string]string

返回指定key对应map类型

GetQueryMap(key string) (map[string]string, bool)

同上,会返回状态

PostForm(key string) string

该方法返回一个从POST 请求的urlencode表单或者multipart表单数据,不存在时返回空字符串

DefaultPostForm(key, defaultValue string) string

同上,key不存在时返回默认值

GetPostForm(key string) (string, bool)

同PostForm()方法,并且会返回状态

PostFormArray(key string) []string

该方法返回指定key的字符串类型的slice

GetPostFormArray(key string) ([]string, bool)

同上,并返回状态

PostFormMap(key string) map[string]string

返回指定key的map类型

GetPostFormMap(key string) (map[string]string, bool)

同上,并返回状态

FormFile(name string) (*multipart.FileHeader, error)

返回指定key的第一个文件(用作文件上传)

MultipartForm() (*multipart.Form, error)

该方法解析multipart表单,包含file文件上传

SaveUploadedFile(file *multipart.FileHeader, dst string) error

该方法用来上传指定的文件头到目标路径(dst)

5.2 Bind函数

此组函数也是用于处理请求参数的,不过封装得更好,一方面能够直接将请求参数映射到一个结构体类型中,同时可以进行合法性检查,内置的有json, xml, protobuf, form, query, yaml。这些Bind极大的减少我们自己去解析各种个样的数据格式, 提高我们的开发速度,Bind的实现都在gin/binding里面。

  • 这些方法底层使用MustBindWith;
  • 如果存在绑定错误,请求将被以下指令中止 c.AbortWithError(400, err).SetType(ErrorTypeBind),响应状态代码会被设置为400,请求头Content-Type被设置为text/plain; charset=utf-8;
  • 注意,如果你试图在此之后设置响应代码,将会发出一个警告 [GIN-debug] [WARNING] Headers were already written. Wanted to override status code 400 with 422,如果你希望更好地控制行为,请使用ShouldBind相关的方法。

函数

功能

Bind(obj interface{}) error

自动解析Content-Type并绑定到指定的binding引擎

BindJSON(obj interface{}) error

支持MIME为application/json的解析

BindXML(obj interface{}) error

支持MIME为application/xml的解析

BindQuery(obj interface{}) error

只支持QueryString的解析, 和Query()函数一样

BindYAML(obj interface{}) error

支持MIME为application/x-yaml的解析

BindHeader(obj interface{}) error


BindUri(obj interface{}) error

只支持路由变量的解析

MustBindWith(obj interface{}, b binding.Binding) error

使用指定的binding引擎来绑定传递的结构体指针(当有任何错误时,终止请求并返回400)

5.3 ShouldBind函数

类似于Bind函数,Context还提供了一组ShouldBind函数,这些方法底层使用ShouldBindWith,如果存在绑定错误,则返回错误,开发人员可以正确处理请求和错误。

6 Header处理

函数

功能

Status(code int)

设置响应码

Header(key, value string)

(1)如果value不为空,则在响应体重写入一个header;
(2)如果value为空,则删除响应体的中的header。

GetHeader(key string) string

返回请求体中的heade

7 Cookie处理

  • SetCookie(name, value string, maxAge int, path, domain string, secure, httpOnly bool): 该方法将设置一个Set-Cookie到响应头中;
  • Cookie(name string) (string, error): 返回名称为name的cookie。
标签列表
最新留言