这是我参与8月更文挑战的第31天,活动详情查看:8月更文挑战
Go的http有两个核心功能:Conn、ServeMux
Go 提供了一系列用于创建 Web 服务器的标准库,而且通过 Go 创建一个服务器的 步骤非常简单,只要通过 net/http 包调用 ListenAndServe 函数并传入网络地址以及负责处理请求的处理器( handler ) 作为参数就可以了。
如果网络地址参数为空字符串,那 么服务器默认使用 80 端口进行网络连接;如果处理器参数为 nil,那么服务器将使用默认的多路复用器 DefaultServeMux,
Conn的goroutine
与我们一般编写的http服务器不同, Go为了实现高并发和高性能, 使用了goroutines来处理Conn的读写事件, 这样每个请求都能保持独立,相互不会阻塞,可以高效的响应网络事件。这是Go高效的保证。
Go在等待客户端请求里面是这样写的:
1 | go复制代码c, err := srv.newConn(rw) |
这里我们可以看到客户端的每次请求都会创建一个Conn,这个Conn里面保存了该次请求的信息,然后再传递到对应的handler,该handler中便可以读取到相应的header信息,这样保证了每个请求的独立性。
ServeMux的自定义
我们前面小节讲述conn.server的时候,其实内部是调用了http包默认的路由器,通过路由器把本次请求的信息传递到了后端的处理函数。那么这个路由器是怎么实现的呢?
它的结构如下:
1 | go复制代码type ServeMux struct { |
下面看一下muxEntry
1 | csharp复制代码type muxEntry struct { |
接着看一下Handler的定义
1 | go复制代码type Handler interface { |
Handler是一个接口,但是前一小节中的sayhelloName
函数并没有实现ServeHTTP这个接口,为什么能添加呢?原来在http包里面还定义了一个类型HandlerFunc
,我们定义的函数sayhelloName
就是这个HandlerFunc调用之后的结果,这个类型默认就实现了ServeHTTP这个接口,即我们调用了HandlerFunc(f),强制类型转换f成为HandlerFunc类型,这样f就拥有了ServeHTTP方法。
1 | scss复制代码type HandlerFunc func(ResponseWriter, *Request) |
路由器里面存储好了相应的路由规则之后,那么具体的请求又是怎么分发的呢?请看下面的代码,默认的路由器实现了ServeHTTP
:
1 | erlang复制代码func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { |
如上所示路由器接收到请求之后,如果是*
那么关闭链接,不然调用mux.Handler(r)
返回对应设置路由的处理Handler,然后执行h.ServeHTTP(w, r)
也就是调用对应路由的handler的ServerHTTP接口,那么mux.Handler(r)怎么处理的呢?
1 | scss复制代码func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) { |
Go其实支持外部实现的路由器 ListenAndServe
的第二个参数就是用以配置外部路由器的,它是一个Handler接口,即外部路由器只要实现了Handler接口就可以,我们可以在自己实现的路由器的ServeHTTP里面实现自定义路由功能。
如下代码所示,我们自己实现了一个简易的路由器
1 | go复制代码package main |
Go 提供了一系列用于创建 Web 服务器的标准库,而且通过 Go 创建一个服务器的 步骤非常简单,只要通过 net/http 包调用 ListenAndServe 函数并传入网络地址以及负责处理请求的处理器( handler ) 作为参数就可以了。
如果网络地址参数为空字符串,那 么服务器默认使用 80 端口进行网络连接;如果处理器参数为 nil,那么服务器将使用默认的多路复用器 DefaultServeMux,当然,我们也可以通过调用 NewServeMux 函数创建一个多路复用器。多路复用器接收到用户的请求之后根据请求的 URL 来判断使用哪 个处理器来处理请求,找到后就会重定向到对应的处理器来处理请求
使用默认的多路复用器(DefaultServeMux)
1 | go复制代码package main |
使用自己创建的多路复用器
在创建服务器时,我们还可以通过 NewServeMux 方法创建一个多路复用器
1 | go复制代码func NewServeMux() *ServeMux |
NewServeMux创建并返回一个新的*ServeMux
1 | go复制代码package main |
结构体 ServeMux
1 | go复制代码type ServeMux struct { |
ServeMux类型是HTTP请求的多路转接器。它会将每一个接收的请求的URL与一个注册模式的列表进行匹配,并调用和URL最匹配的模式的处理器。
结构体 ServeMux 的相关方法
func (*ServeMux)
1 | go复制代码func (mux *ServeMux) Handle(pattern string, handler Handler) |
Handle注册HTTP处理器handler和对应的模式pattern。如果该模式已经注册有一个处理器,Handle会panic。
func (*ServeMux)
1 | go复制代码func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) |
HandleFunc注册一个处理器函数handler和对应的模式pattern。
func (*ServeMux)
1 | scss复制代码func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) |
Handler根据r.Method、r.Host和r.URL.Path等数据,返回将用于处理该请求的HTTP处理器。它总是返回一个非nil的处理器。如果路径不是它的规范格式,将返回内建的用于重定向到等价的规范路径的处理器。
Handler也会返回匹配该请求的的已注册模式;在内建重定向处理器的情况下,pattern会在重定向后进行匹配。如果没有已注册模式可以应用于该请求,本方法将返回一个内建的”404 page not found”处理器和一个空字符串模式。
func (*ServeMux)
1 | scss复制代码func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) |
ServeHTTP将请求派遣到与请求的URL最匹配的模式对应的处理器。
使用实现ServerHTTP的类型来自定义的处理器处理请求
1 | go复制代码package main |
通过 Server 结构对服务器进行更详细的配置
Server结构体也定义了实现http的相关方法
1 | go复制代码package main |
本文转载自: 掘金