HTTP库
request概览
- Body和GetBody Body: 只能调用一次; 再次读取, 啥也读不到, 但也不会报错 GetBody: 原则上可以多次读取, 但是在原生的http.Request里面, 这个是nil 在读取到body之后, 我们就可以用于反序列化, 比如说把json格式的字符串转换为一个对象等
- Query
除了Body, 我们还可能传递参数的地方是Query
也就是通过
values := r.URL.Query()获取请求参数
Query也可能出数组的 所有的值都被解释为字符串, 所以需要自己解析为数字等
- Request URL URL里的Host不一定有值 r.Host一般都有值, 是Host这个header的值 RawPath也不一定有 Path肯定有
- Method
- Request Header header大体上是两类, 一类是http预定义的; 一类是自己定义的 Go会自动将header名字转为标准名字 -- 其实就是大小写调整 一般用X开头来表明自己定义的, 比如说 X-mycompany-your=header
- Form Form和PasrseForm 要先调用ParseForm 建议加上 Content-Type: application/x-www-form-urlencoded
- ...
// map[key]value
// 这里就是定义了一个map
// map的key是string
// map的value是[]string, string的切片
type Values map[string][]string
要点总结
- Body和GetBody 重点在于Body是一次性的, 而GetBody默认情况下是没有, 一般中间件会注入这个方法
- URL 注意URL里面的字段的含义坑并不如你期望的那样
- Form 记得调用前先用ParseForm, 别忘了请求头里面记上http头
基础语法 type
type定义
type 名字 interface {}里面只能有方法, 方法也不需要有func关键字 接口是一组行为的抽象 尽量用接口, 以实现面向接口编程
type Server interface {
Route(pattern string, handler http.HandlerFUnc)
Start(address string) error
}
type 名字 struct {}结构体和结构体的字段都遵循大小写控制访问性的原则
type Name struct {
fieldName FieldType
// ...
}
type 名字 别的类型type 别名 = 别的类型
结构体初始化
- Go没有构造函数
- 初始化语法 Struct{}
- 获取指针: &Struct{}
- 获取指针2: new(Struct)
- new可以理解为Go会为你的变量分配内存, 并且把内存都置为0
// duck1 是 *ToyDuck
duck1 := &ToyDuck{}
duck1.Swim()
duck2 := ToyDuck{}
duck2.Swim()
// duck3 你 *ToyDuck
duck3 := new(ToyDuck)
duck3.Swim()
// 当你声明成这样的时候, Go回帮你分配好内存
// 不用担心空指针的问题, 因为它压根就不是指针
var duck4 ToyDuck
duck4.Swim()
// duck5 就是一个指针, 不会帮助分配内存
var duck5 *ToyDuck
// 直接回panic
duck5.Swim()
// 赋值, 初始化按字段名字赋值
duck6 := ToyDuck{
Color: "黄色",
Price: 100
}
// 赋值, 按字段顺序赋值
duck7 := ToyDuck{"蓝色", 1024}
duck7.Swim()
// 后赋值
duck8 := ToyDuck{}
duck8.Color: "橘色"
指针与方法接收器
和C, C++一样, *表示指针, &取地址
如果声明了一个指针, 但没有被复制, 那么他就是nil
结构体自引用
结构体内部引用自己, 只能使用指针 准确来说, 在整个引用链上, 如果构成循环, 那就只能用指针
type Node struct {
// 不合法, 因为在创建的时候需要计算大小
// left Node
// right Node
left *Node
right *Node
}
方法接收器
type User struct {
Name string
Age int
}
// 结构体接收器
func(u User) ChangeName(newName string) {
u.Name = newName
}
// 指针接收器
func(u *User) ChangeAge(newAge int) {
u.Age = newAge
}
u1 := User {"Tom", 10}
// 不会改变
u1.ChangeName("newTom")
// 会改变
u1.ChangeAge(11)
u2 := &User {"Tom", 10}
// 不会改变
u2.ChangeName("newTom")
// 胡改变
u2.ChangeAge(11)
// 只有指针接收器可以改变struct
// 遇事不决用指针
结构体如何实现接口
当看到一直鸟走路像鸭子, 游泳像鸭子, 叫起来也像鸭子, 那么这只鸟就可以被称为鸭子.
当一个结构体具备接口的所有的方法时, 它就实现了这个接口.(并不需要引入接口所在的包)
type Server interface {
Route(pattern string, handleFunc http.HandlerFunc)
Start(address string) error
}
type sdkHttpServer struct {
Name string
}
func(s *sdkHttpServer) Route(pattern string, handleFUnc http.HandlerFunc) {
panic("implement me")
}
func(s *sdkHttpServer) Start(address string) error {
panic("implement me")
}
最好现有抽象, 再有实现, 所以要先定义接口
Server与Context抽象
context保存用户http请求的上下文, request, response, 等
func (c *Context) OkJson(resp interface{}) error {
return c.WriteJson(http.StatusOK, resp)
}
做了一层封装
空接口interface{} 类似Object, 是所有对象的基类; 任何结构体都实现了该接口
json库
- 用于处理json格式字符串
- 字段后面的内容被称为Tag, 即标签, 运行期间可以反射拿到
- json根据json Tag来完成json到结构体的映射
- 典型的声明式API设计
type signUpReq struct {
// Tag
Email string `json:"email"`
Password string `json:"password"`
ConfirmedPassword string `json:"confirmed_password"`
}
HTTP server -- 进一步封装
- 提供辅助方法
- 不是Context本身必须提供的方法.