go的http详解

       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函数处理请求
}



  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值