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

2024-01-07 18:50:31

net/http/server.go

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

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

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响应的方法

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

最基本的结构体

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 的映射关系

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模式和对应的处理程序

type muxEntry struct {

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

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

文章来源:https://blog.csdn.net/2301_78179333/article/details/135385201
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。