golang中net/http/server.go源码剖析

golang中net/http源码剖析

net/http/server.go

首先,文件开头定义了一些错误变量,这些错误变量用于表示在处理HTTP请求和响应过程中可能出现的一些错误情况

go 复制代码
var (
	//表示当HTTP方法或响应状态码不允许有请求体时,ResponseWriter.Write调用会返回此错误
	ErrBodyNotAllowed = errors.New("http: request method or response status code does not allow body")
	
	//表示当底层连接已被Hijacker接口劫持时,调用ResponseWriter.Write会返回此错误
	//在被劫持的连接上进行零字节写入将会返回ErrHijacked而不会有其他副作用
	ErrHijacked = errors.New("http: connection has been hijacked")

 	//表示当处理程序设置了带有声明大小的Content-Length响应头,并尝试写入的字节数超过声明大小时,ResponseWriter.Write调用会返回此错误
	ErrContentLength = errors.New("http: wrote more than the declared Content-Length")
	
	//一个已废弃的错误变量,不再被net/http包中的任何内容返回
	//调用者不应该将错误与此变量进行比较
	ErrWriteAfterFlush = errors.New("unused")
)

Handler

go 复制代码
type Handler interface {
	ServeHTTP(ResponseWriter, *Request)
}

Handler接口用于处理HTTP请求

Handler接口包含了一个ServeHTTP方法,该方法接收一个ResponseWriter和一个*Request作为参数。当HTTP服务器接收到请求时,会调用ServeHTTP方法来处理请求并生成响应

根据 http 请求 Request 中的请求路径 path 映射到对应的 handler 处理函数,对请求进行处理和响应

其中关于源码中的注释

  1. ServeHTTP方法的作用是写入响应头和数据到ResponseWriter,然后返回。返回信号表示请求处理完成;在ServeHTTP调用完成之后或并发地使用ResponseWriter或读取Request.Body是无效的。
  2. 由于HTTP客户端软件、HTTP协议版本以及客户端和Go服务器之间的中间件的不同,可能无法在向ResponseWriter写入数据之后从Request.Body中读取数据。因此,谨慎的处理程序应该先读取Request.Body,然后再进行响应。
  3. 除了读取请求体之外,处理程序不应修改提供的Request。
  4. 如果ServeHTTP方法发生panic(意外的运行时错误),服务器会假定panic的影响仅限于当前的请求。服务器会恢复panic,将堆栈跟踪记录到服务器错误日志,并关闭网络连接或者发送HTTP/2的RST_STREAM,具体取决于HTTP协议。如果要中断处理程序,以便客户端看到中断的响应但服务器不记录错误,可以panic并使用值ErrAbortHandler

ResponseWriter

ResponseWriter接口定义,用于处理HTTP响应的方法

go 复制代码
type ResponseWriter interface {
	//其中type Header map[string][]string 表示HTTP标头中的键值对
	Header() Header
	Write([]byte) (int, error)
	WriteHeader(statusCode int)
}

WriteHeader(statusCode int)

WriteHeader(statusCode int)方法发送具有提供的状态码的HTTP响应头。如果没有显式调用WriteHeader,则对Write的第一次调用会触发隐式的WriteHeader(http.StatusOK)。因此,显式调用WriteHeader主要用于发送错误代码或1xx信息响应。提供的代码必须是有效的HTTP 1xx-5xx状态代码。可以写入任意数量的1xx头部,然后最多写入一个2xx-5xx头部。1xx头部会立即发送,但2xx-5xx头部可能会被缓冲。使用Flusher接口来发送缓冲的数据。在发送2xx-5xx头部时,头部映射会被清除,但在发送1xx头部时不会被清除。

Write([]byte) (int, error)

Write([]byte) (int, error)方法将数据作为HTTP响应的一部分写入到连接中。它返回写入的字节数和可能的错误。如果在调用WriteHeader之前尚未调用WriteHeader,则Write在写入数据之前会调用WriteHeader(http.StatusOK)。如果头部不包含Content-Type行,则Write会添加一个Content-Type行,该行设置为将前512个字节的写入数据传递给DetectContentType的结果。此外,如果所有写入数据的总大小不到几KB,并且没有调用Flush,则Content-Length头部会被自动添加。

Header()

Header()方法返回一个Header类型的对象,该对象表示将被WriteHeader发送的响应头。Header类型是一个映射,用于存储HTTP响应头的键值对。Header对象也是处理程序设置HTTP尾部的机制。如果在调用WriteHeader(或Write)之后修改了头部映射,则除非HTTP状态码属于1xx类或修改的头部是尾部,否则不会产生任何效果

这些方法和规范定义了ResponseWriter接口,该接口用于生成HTTP响应。这些规范非常重要,因为它们确保了HTTP服务器和处理程序之间的正确交互,以及在处理并发请求时的正确行为。

Server

最基本的结构体

go 复制代码
type Server struct {
	//表示服务器的网络地址,格式为host:port
	Addr string

	//表示处理HTTP请求的处理程序。它是一个接口类型,通常会使用http.Handler或http.HandlerFunc
	Handler Handler 

	//一个布尔值,用于指示是否禁用通用选项处理程序
	DisableGeneralOptionsHandler bool
	
	//表示服务器的TLS配置,用于启用HTTPS
	TLSConfig *tls.Config
	
	//表示从接收请求开始到读取请求主体的超时时间
	ReadTimeout time.Duration

	//表示读取请求头的超时时间
	ReadHeaderTimeout time.Duration

	//表示写入响应的超时时间
	WriteTimeout time.Duration
	
	//表示空闲连接的超时时间
	IdleTimeout time.Duration
	
	//表示请求头的最大字节数
	MaxHeaderBytes int
	
	//表示用于处理TLS下一级协议的映射
	TLSNextProto map[string]func(*Server, *tls.Conn, Handler)

	//表示连接状态变化时的回调函数
	ConnState func(net.Conn, ConnState)
	
	//表示用于记录错误日志的Logger
	ErrorLog *log.Logger
	
	//表示用于创建基础上下文的函数
	BaseContext func(net.Listener) context.Context
	
	//表示用于创建连接上下文的函数
	ConnContext func(ctx context.Context, c net.Conn) context.Context
	
	//表示服务器是否处于关闭状态的原子布尔值
	inShutdown atomic.Bool 
	
	//表示是否禁用长连接的原子布尔值
	//长连接是指在客户端和服务器之间建立的TCP连接,在这个连接上可以发送多个HTTP请求和响应
	//相当于短连接是指在客户端和服务器之间建立的TCP连接只用于发送一个单独的HTTP请求和响应
	disableKeepAlives atomic.Bool
	
	//确保nextProtoErr只被设置一次的sync.Once对象
	nextProtoOnce     sync.Once 
	
	//表示下一级协议的错误
	nextProtoErr      error     

	//用于保护listeners和activeConn字段的互斥锁
	mu         sync.Mutex
	
	//表示服务器的监听器
	listeners  map[*net.Listener]struct{}
	
	//表示当前活动的连接
	activeConn map[*conn]struct{}
	
	//表示在服务器关闭时需要执行的函数列表
	onShutdown []func()
	
	//用于等待所有监听器都关闭的WaitGroup
	listenerGroup sync.WaitGroup
}

ServeMux

ServeMux是一个HTTP请求多路复用器,它是net/http包中的一个结构体,用于匹配每个传入请求的URL,并根据注册的模式调用与URL最匹配的处理程序

ServeMux 是对 Handler 的具体实现,内部通过一个 map 维护了从 path 到 handler 的映射关系

go 复制代码
type ServeMux struct {

	//用于保护m和es字段的读写锁
	mu    sync.RWMutex
	
	//用于将URL模式映射到对应的处理程序
	//muxEntry结构体包含了实际的处理程序和一些其他信息
	m     map[string]muxEntry

	es    []muxEntry //从最长到最短排序的条目切片
	hosts bool       // 是否有任何模式包含主机名
}

ServeMux结构体的主要作用是根据注册的模式来选择处理程序,并根据请求的URL来调用匹配的处理程序。它还负责对URL请求路径和Host头进行清理,去除端口号,并将包含.或...元素或重复斜杠的请求重定向到等效的更干净的URL

muxEntry

muxEntry用于表示ServeMux中的一个条目,其中包含了URL模式和对应的处理程序

go 复制代码
type muxEntry struct {

	//表示一个处理程序,通常是实现了http.Handler接口的对象,用于处理与该URL模式匹配的请求
	h       Handler
	
	//表示一个URL模式,用于匹配传入请求的URL
	//这个URL模式可以包含通配符或者特定的路径,用于指定与之匹配的请求路径
	pattern string
}

其中在ServeMux中,muxEntry结构体被用来表示每一个注册的URL模式和对应的处理程序,它们被存储在m和es字段中,用于在接收到请求时进行匹配和调度。muxEntry结构体是ServeMux实现请求路由功能的重要组成部分

相关推荐
间彧42 分钟前
Spring Cloud Gateway与Kong或Nginx等API网关相比有哪些优劣势?
后端
间彧44 分钟前
如何基于Spring Cloud Gateway实现灰度发布的具体配置示例?
后端
间彧44 分钟前
在实际项目中如何设计一个高可用的Spring Cloud Gateway集群?
后端
间彧1 小时前
如何为Spring Cloud Gateway配置具体的负载均衡策略?
后端
间彧1 小时前
Spring Cloud Gateway详解与应用实战
后端
爱吃小胖橘1 小时前
Unity网络开发--超文本传输协议Http(1)
开发语言·网络·网络协议·http·c#·游戏引擎
EnCi Zheng2 小时前
SpringBoot 配置文件完全指南-从入门到精通
java·spring boot·后端
烙印6012 小时前
Spring容器的心脏:深度解析refresh()方法(上)
java·后端·spring
Lisonseekpan3 小时前
Guava Cache 高性能本地缓存库详解与使用案例
java·spring boot·后端·缓存·guava
4 小时前
JUC专题 - 并发编程带来的安全性挑战之同步锁
后端