gin responseWriter 详解
这里所说的 responseWriter
是 Context
里面的
writermem responseWriter
。
这个 responseWriter
实际上只是对
http.ResponseWriter
的一个扩展 struct
。
也就是说,对于 responseWriter
,我们可以通过它来调用
http.ResponseWriter
的几个方法,也可以调用
responseWriter
自身实现的一些其他的方法,具体有下面这些方法:
WriteHeaderNow
: 写响应头(如果还没开始写响应)WriteString
: 返回字符串响应。Status
: 获取状态码Size
: 获取响应大小Written
: 是否已经开始往http.ResponseWriter
写入数据
它也重写了 http.ResponseWriter
的一些方法:
WriteHeader
: 如果已经开始写响应数据了,就打印警告,否则直接修改 响应状态码。Write
: 还没有写响应头的时候,先写响应头。然后写入数据,并且记录响应的大小。Hijack
: 一个Hijack
的包裹函数,没有其他作用Flush
: 将数据发送给客户端。如果没有写入 header,就先写入 header
总之,这里只是封装了一些最基本的函数,就是满足我们写 header 跟 body 的需求。如果我们需要写入诸如 JSON 之类的数据,其实是需要继续在此基础上进行封装的。
思维导图
gin context 结构体属性含义
前言
有一定 go 使用经验的人应该知道,context
在 go 的 web
开发中往往代表着一个请求的上下文。
作为开发者,我们可以通过这个 context
实例,实现对请求
goroutine 链条的管理,比如请求的超时控制等等。
不过,net/http
里面的 ServeHTTP
方法只是给了开发者两个参数,一个是
http.ResponseWriter
,是用来返回响应给客户端用的,另一个是
*http.Request
,是用来获取请求信息的。但实际上
*http.Request
包含了请求相关的 context
,这个
context
就是整个请求最初的那个 context
。
对于 Web 开发来说,有了 http.ResponseWriter
和
*http.Request
这两个参数也足够了。但是想要更高效地进行应用开发,我们往往需要在此基础上再封装一下。
在 gin 里面,也对 baseContext 进行了一定的扩展吧,应该这么说,实现了很多 Web 基础功能,比如参数获取、中间件、参数验证等等。
gin.context 思维导图
看不清可以右键在新页面打开.
go切片参数传递用值还是指针
Go 中常用的切片 slice 数据结构是动态数组,切片长度并不固定,在容量不足的时候会自动扩容。
切片实质上是对一个底层数组的抽象视图,由 Go
运行时维护。在运行时,切片由如下的 SliceHeader
结构体表示,其中 Data
字段是指向底层数组的指针,Len
表示当前切片的长度,而
Cap
表示当前切片的容量,也就是 Data
数组的大小。
1 | type SliceHeader struct { |
切片作为参数入参
我们知道 slice
是一个指针类型,所以我们可能会习惯性地认为:传递切片,等同于传递指针,函数内部对切片的修改,将会影响到函数外部的切片。这一习惯性认知在大部分情况下都是正确的,如以下代码所示:在
test
函数中修改切片,外部的 TestSlice
受到了影响。
1 | func test(s []string) { |
输出: 1
2[a b]
[b b]
我们对上面的代码做一些修改,在调用函数的时候触发切片的扩容机制,然后再看看输出:
1 | func test1(s []string) { |
输出:
1 | [a b] |
我们可以发现,test1
里面对切片的修改并没有完全影响到外部的切片。
原因
在 Go 中,函数参数传递机制为 值拷贝。
将切片做为函数参数传递,实际上是拷贝了 SliceHeader
结构体传入参数,结构体包含了指向底层数组的指针,因此在函数内部修改切片,操作的底层数组是一样的。
但是如果函数内的切片触发了切片扩容(如:使用 append
追加元素),Go
运行时会为切片分配一块新的内存空间并将原切片的所有元素拷贝过去,函数内部切片的底层数组指针指向了
新分配 的内存空间,而函数外部切片底层数组指针仍指向
分配前 的地址空间,由此出现了内外切片不一致的情形。
建议
- 操作不涉及切片容量变化,直接传递切片
- 操作涉及切片容量变化,且需要反馈给调用放,传递切片指针。
gin切片表单验证
在 gin
里面,我们可以定义一个带切片类型字段的结构体来对切片做表单验证,需要注意的是:
* 对应字段为切片类型 * form
tag 里面的键为
ids[]
的形式(如果是 query 的数组或者 form
里面的数组,如果是 json body 里面就不用 ids[]=
这样传递数组参数) * binding
里面可以使用 dive
来对数组的每一项做验证
1 | package main |