Go提供了一个完善的net/http包用于搭建web服务器,同时http能很简单的对web的路由进行设置和操作。
http包建立的简单的web服务器,路由器的配置,请求的监听和处理。
package main
import (
"fmt"
"net/http"
"log"
)
type sayHello struct{
}
func (s *sayHello) ServeHTTP(w http.ResponseWriter, r *http.Request){
fmt.Println("sayhello")
fmt.Fprintf(w,"sayhello")
}
func hello(w http.ResponseWriter, r *http.Request){
fmt.Println("hello")
fmt.Fprintf(w,"hello")
}
func main(){
t:=&sayHello{}
http.HandleFunc("/",hello)
http.Handle("/index",t)
http.ListenAndServe(":8080",nil)
}
路由器的配置
http服务端程序主要有内部默认路由器和外部自定义路由器。
内部默认的路由器结构:
var DefaultServeMux = &defaultServeMux//内部默认路由器
var defaultServeMux ServeMux
type ServeMux struct {
mu sync.RWMutex//同步锁,用于涉及并发的请求处理
m map[string]muxEntry//路由规则,一个string对应一个muxEntry
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
explicit bool//是否精确匹配
h Handler//路由对应的handle
pattern string//匹配字符串
}
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
http包中有两个注册内部路由规则的方法:Handle函数和HandleFunc函数,这两个函数底层都
是调用了DefaultServerMux对象的Handle函数。
type HandlerFunc func(ResponseWriter, *Request)// HandlerFunc实现ServeHTTP方法,得以适配handler接口
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
//通过传入实现ServeHTTP方法的类型
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
//通过传入func(ResponseWriter, *Request)类型的方法,注册路由
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
mux.Handle(pattern, HandlerFunc(handler))
}//底层的路由存储,以string-muxEntry的形式存到DefaultServeMux的m中
func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.mu.Lock()
defer mux.mu.Unlock()
if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
mux.m[pattern] = muxEntry{explicit: true, h: handler, pattern: pattern}
if pattern[0] != '/' {
mux.hosts = true
}
n := len(pattern)
if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit {
path := pattern
if pattern[0] != '/' {
path = pattern[strings.Index(pattern, "/"):]
}
url := &url.URL{Path: path}
mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(url.String(), StatusMovedPermanently), pattern: pattern}
}
}
外部自定义路由器
外部自定义路由就是定义一个struct实现ServeHTTP函数,在ServeHTTP中进行路由转发。
package main
import (
"fmt"
"net/http"
)
type MyMux struct {
}
func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
hello(w, r)
return
}
http.NotFound(w, r)
return
}
func hello(w http.ResponseWriter, r *http.Request){
fmt.Println("hello")
fmt.Fprintf(w,"hello")
}
func main() {
mux := &MyMux{}
http.ListenAndServe(":9090", mux)
}
请求监听和处理
从web服务端处理程序可以看到ListenAndServe函数进行了端口的监听,接收请求,分配handle进行
请求处理。函数的底层实现主要是初始化一个server对象,然后调用net.Listen("tcp", addr)利用tcp进行端
口监听,然后通过server对象的Serve函数进行http请求的接收和处理。
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler}
return server.ListenAndServe()
}
func (srv *Server) ListenAndServe() error {
addr := srv.Addr
……
ln, err := net.Listen("tcp", addr)
……
return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})
}
server对象的Serve函数的实现
func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
var tempDelay time.Duration // how long to sleep on accept failure
for {
rw, e := l.Accept()
if e != nil {
if ne, ok := e.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
time.Sleep(tempDelay)
continue
}
return e
}
tempDelay = 0
c := srv.newConn(rw)//对于每个请求实例化一个conn对象
c.setState(c.rwc, StateNew) // before Serve can return
go c.serve(ctx)//开启一个goroutine接收数据并处理
}
}
func (c *conn) serve(ctx context.Context) {
……
for {//读取请求数据
w, err := c.readRequest(ctx)
……
serverHandler{c.server}.ServeHTTP(w, w.req)
……
}
}
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
handler := sh.srv.Handler//ListenAndServe传入的自定义路由器
if handler == nil {//没有传入自定义路由器
handler = DefaultServeMux//http包的默认路由器
}
handler.ServeHTTP(rw, req)
}
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
……
h, _ := mux.Handler(r)//根据url获取对应的handler
h.ServeHTTP(w, r)//执行handler的ServerHTTP函数处理请求
}