likes
comments
collection
share

避坑Go的http包

作者站长头像
站长
· 阅读数 59

写在前面

之前在七天实现Web框架的专栏中讲到过Go内置的net/http包启动一个服务,那篇文章没有详细解释对于http.ResponseWriterhttp.Request两个结构体的具体使用和特别注意事项。这里算是补上那个坑。在最初的Web框架实现中,并没有考虑到这些注意事项,后续会继续将这些潜在的bug给修复。

响应ResponseWriter的坑

避坑Go的http包 上图是内置http包中响应的接口定义。从中也能看出,一个HTTP响应比较重要的三个东西

  • 响应头【Header】
  • 响应体【Write】
  • 状态码【WriteHeader】

坑1——WriterHeader

在业务逻辑中如果使用http.ResponseWriter的WriterHeader方法设置状态码,后续状态码就不能再修改了

避坑Go的http包

坑2——Writer

在业务逻辑中,如果使用http.ResponseWriter的Writer方法向客户端写入数据,响应头字段就不能再修改了

避坑Go的http包

坑3——Header

  1. 在业务逻辑中,http.ResponseWriter的Header方法设置响应头,它必须必须在首次使用Writer之前使用
  2. 向响应头中写入自定义的信息,最好是以X开头,并且单词与单词之间用连字符链接。X-Auth-Token

避坑Go的http包

请求Request坑

type Request struct {
   Method string

   URL *url.URL

   Proto      string // "HTTP/1.0"
   ProtoMajor int    // 1
   ProtoMinor int    // 0

   Header Header
   
   Body io.ReadCloser
   
   GetBody func() (io.ReadCloser, error)
   
   ContentLength int64

   TransferEncoding []string

   Close bool
   
   Host string

   Form url.Values
   
   PostForm url.Values

   MultipartForm *multipart.Form

   Trailer Header
   
   RemoteAddr string
   
   RequestURI string

   TLS *tls.ConnectionState
   Cancel <-chan struct{}
   Response *Response
   ctx context.Context
}

坑1——Body

  1. 不知道大家有没有遇到这样的问题,就是我在中间件中读取完了请求体中的数据,然后在视图函数中再次读取就拿不到数据了。这就是他的坑
  2. 我们先看下这个Body具体是个什么东西

避坑Go的http包 3. 它是一个接口来着,并且对于http.Request中的Body具体实现,是只能读一次的。所以当我们想要在上下文中缓存请求体中的数据怎么办

  • 方式一:自己构建一个io.ReadCloser,保存请求中的Body数据,下次读取直接从这个字段中读取
  • 方式二:使用http.Request.GetBody()方法,用这个方法缓存请求中的Body数据。在上图中,Request结构体中的最后一个属性是GetBody,它是一个方法类型的属性。默认是nil的,但是当我们初始化,或者说给这个方法设置一个自定义的方法,它就能为我们所用了。我们的想法是:在这个方法中,将请求中的Body缓存起来。
func main(){
    // 内置方法MaxBytesReader
    // 第一个参数:可写的IO流
    // 第二个参数:可读的IO流
    // 第三个参数:最大可读字节
    // MaxBytesReader
    req.Body = http.MaxBytesReader(w, req.Body, maxRequestBodySize)
    body1, err := ioutil.ReadAll(req.GetBody())
    body2, err := ioutil.ReadAll(req.GetBody()) 
    // 读取两次,获取到同样的数据
    req.Body.Close()
}

避坑Go的http包

坑2——Query

避坑Go的http包

  • 查询参数:http://www.baidu.com?username=neo?password=neo123
  • 这里需要注意的是,调用Query方法,返回来的是一个[]string切片
  • 并且所有的值都是string类型,如需类型转换需要自己手动实现

坑3——Header

避坑Go的http包

  • 一般来说,请求中的Header大体上分为两类
    • HTTP预定义的
    • 自定义的
  • Go会自动将请求的Header中的名字转换为标准的名字——就是调整大小写
  • 一般用X开头来表明自定义的字段。X-Auth-Token

坑4——Form表单

避坑Go的http包

  1. 使用这两个Form之前,必须先调用ParseForm方法,这是将请求体中的数据解析到这些字段中。

避坑Go的http包 2. Form:解析URL中的查询参数、POST、PATCH、PUT的表单数据 3. PostForm:解析PATCH、POST、PUT的表单数据

转载自:https://juejin.cn/post/7224682976651165756
评论
请登录