您的位置:首页 > 理论基础 > 计算机网络

go的http详解

2017-04-29 19:17 302 查看
       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函数处理请求
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  golang http web