GO语言HTTP

HTTP

超文本传输协议(Hypertext Transfer Protocol、HTTP 协议)

设计原理

HTTP 协议是应用层协议,在通常情况下我们都会使用 TCP 作为底层的传输层协议传输数据包,但是 HTTP/3 在 UDP 协议上实现了新的传输层协议 QUIC 并使用 QUIC 传输数据,这也意味着 HTTP 既可以跑在 TCP 上,也可以跑在 UDP 上。

HTTP 与传输层协议

Go 语言标准库通过 net/http 包提供 HTTP 的客户端和服务端实现, 作为文本传输协议,HTTP 协议的协议头都是文本数据

HTTP 协议目前主要还是跑在 TCP 协议上的,TCP 协议是面向连接的、可靠的、基于字节流的传输层通信协议2

层级结构

Go 语言的 net/http 中同时包好了 HTTP 客户端和服务端的实现,为了支持更好的扩展性,它引入了 net/http.RoundTripper 和 net/http.Handler 两个接口。

HTTP 请求的接收方可以实现 net/http.Handler 接口,其中实现了处理 HTTP 请求的逻辑,处理的过程中会调用 net/http.ResponseWriter 接口的方法构造 HTTP 响应,它提供的三个接口 Header、Write 和 WriteHeader 分别会获取 HTTP 响应、将数据写入负载以及写入响应头:
type Handler interface {
ServeHTTP(ResponseWriter, *Request)}

type ResponseWriter interface {
Header() Header
Write([]byte) (int, error)
WriteHeader(statusCode int)}

客户端

客户端可以直接通过 net/http.Get 使用默认的客户端 net/http.DefaultClient 发起 HTTP 请求,也可以自己构建新的 net/http.Client 实现自定义的 HTTP 事务,在多数情况下使用默认的客户端都能满足我们的需求,不过需要注意的是使用默认客户端发出的请求没有超时时间,所以在某些场景下会一直等待下去。

事务和 Cookie
事务和 Cookie 是我们在 HTTP 客户端包为我们提供的两个最重要模块, 本节将从 HTTP GET 请求开始,按照构建请求、数据传输、获取连接以及等待响应几个模块分析客户端的实现原理。当我们调用 net/http.Client.Get 发出 HTTP 时,会按照如下的步骤执行:
1.
调用 net/http.NewRequest 根据方法名、URL 和请求体构建请求;
2.
调用 net/http.Transport.RoundTrip 开启 HTTP 事务、获取连接并发送请求;
3.
在 HTTP 持久连接的 net/http.persistConn.writeLoop 方法中等待响应;

客户端的几大结构体

HTTP 的客户端中包含几个比较重要的结构体,它们分别是 net/http.Client、net/http.Transport 和 net/http.persistConn:
*
net/http.Client 是 HTTP 客户端,它的默认值是使用 net/http.DefaultTransport 的 HTTP 客户端;
*
net/http.Transport 是 net/http.RoundTripper 接口的实现,它的主要作用就是支持 HTTP/HTTPS 请求和 HTTP 代理;
*
net/http.persistConn 封装了一个 TCP 的持久连接,是我们与远程交换消息的句柄(Handle);

构建请求
net/http.Request 表示 HTTP 服务接收到的请求或者 HTTP 客户端发出的请求
net/http.NewRequest 是标准库提供的用于创建请求的方法,这个方法会校验 HTTP 请求的字段并根据输入的参数拼装成新的请求结构体。

net/http.Transport.getConn 是获取连接的方法,该方法会通过两种方法获取用于发送请求的连接:

1. 

调用 net/http.Transport.queueForIdleConn 在队列中等待闲置的连接;
2.
调用 net/http.Transport.queueForDial 在队列中等待建立新的连接;

真正负责解析 HTTP 协议的还是 net/http.ReadResponse服务器
Go 语言标准库 net/http 包提供了非常易用的接口,如下所示,我们可以利用标准库提供的功能快速搭建新的 HTTP 服务:

func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, “Hi there, I love %s!”, r.URL.Path[1:])}

func main() {
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))}

上述的 main 函数只调用了两个标准库提供的函数,它们分别是用于注册处理器的 net/http.HandleFunc 函数和用于监听和处理器请求的 net/http.ListenAndServe,多数的服务器框架都会包含这两类接口,分别负责注册处理器和处理外部请求
注册处理器
HTTP 服务是由一组实现了 net/http.Handler 接口的处理器组成的, 当我们直接调用 net/http.HandleFunc 注册处理器时,标准库会使用默认的 HTTP 服务器 net/http.DefaultServeMux 处理请求,该方法会直接调用 net/http.ServeMux.HandleFunc:

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
mux.Handle(pattern, HandlerFunc(handler))}
上述方法会将处理器转换成 net/http.Handler 接口类型调用 net/http.ServeMux.Handle 注册处理器:处理请求
标准库提供的 net/http.ListenAndServe 可以用来监听 TCP 连接并处理请求,该函数会使用传入的监听地址和处理器初始化一个 HTTP 服务器 net/http.Server,调用该服务器的 net/http.Server.ListenAndServe 方法:
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()}

net/http.Server.ListenAndServe 会使用网络库提供的 net.Listen 监听对应地址上的 TCP 连接并通过 net/http.Server.Serve 处理客户端的请求

net/http.Server.Serve 会在循环中监听外部的 TCP 连接并为每个连接调用 net/http.Server.newConn 创建新的 net/http.conn,它是 HTTP 连接的服务端表示

net/http.ServeMux 是一个 HTTP 请求的多路复用器,它可以接收外部的 HTTP 请求、根据请求的 URL 匹配并调用最合适的处理器

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值