go-restful实战与深入分析之基础篇
来源:互联网 发布:淘宝店招图片大全清新 编辑:程序博客网 时间:2024/04/23 15:26
如果想分析清楚go-restful的工作原理我们这篇先介绍一些go http的基本知识,我将通过多个例子把故事串起来,先看一个最基本的helloworld的例子:
func HelloServer(w http.ResponseWriter, req *http.Request) { io.WriteString(w, "hello, world!\n")}func main() { http.HandleFunc("/hello/", HelloServer) err := http.ListenAndServe(":8080", nil) if err != nil { log.Fatal("ListenAndServe: ", err) }}
测试:
curl 127.0.0.1:8080/hello/
hello, world!
上面这个例子里面通过HandleFunc注册方法和路由。
再看一个例子
package mainimport ( "io" "net/http")type a struct{}func (*a) ServeHTTP(w http.ResponseWriter, r *http.Request) { path := r.URL.String() //获得访问的路径 io.WriteString(w, path)}func main() { http.ListenAndServe(":8080", &a{})//第2个参数需要实现Hander接口的struct,a满足}
测试
curl 127.0.0.1:8080/hello
/hello
通过上面两个例子读者可能已经知道http怎么样使用了。当然你可以通过mux统一包装一下:
package mainimport ( "net/http" "io")func main() { mux := http.NewServeMux() mux.HandleFunc("/h", func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "hello") }) mux.HandleFunc("/bye", func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "byebye") }) mux.HandleFunc("/hello", sayhello) http.ListenAndServe(":8080", mux)}func sayhello(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "hello world")}
这个和第一个用的http直接使用HandleFunc是不是很相似,其实mux只是包装了一下,本质是一回事,看看测试
curl 127.0.0.1:8080/hello
hello world
curl 127.0.0.1:8080/h
hello
三个http基本使用的例子已经讲完了。
在深入讲解代码之前先说一个golang编写一个装饰器模式:
package mainimport "fmt"type HandlerFunc func(a,b string)func (f HandlerFunc) ServeTim(a,b string) { f(a, b)}type Handler interface { ServeTim(x, y string)}func Create(m,n string) { fmt.Println(m,"Create",n)}func Delete(m,n string) { fmt.Println(m,"Delete",n)}func main() { HandlerFunc(Create).ServeTim("333","444") HandlerFunc(Delete).ServeTim("333","444")}
测试:
333 Create 444
333 Delete 444
为什么要写这个装饰器东西呢?应为这个就是http里面使用这种模式装饰各种CURD方法。如果理解了这个,我们接这说。看看第一个helloworld的底层是怎样实现的
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { mux.Handle(pattern, HandlerFunc(handler))}
上面的HandlerFunc就是我上面说的装饰器模式,把具体一个handler方法放进去,后面只要通过
type Handler interface { ServeHTTP(ResponseWriter, *Request)}
里面的ServeHTTP去统一调用就可以了,接着看Handle方法
func (mux *ServeMux) Handle(pattern string, handler Handler) { mux.mu.Lock() defer mux.mu.Unlock() if pattern == "" { panic("http: invalid pattern " + pattern) } if handler == nil { panic("http: nil handler") } if mux.m[pattern].explicit { panic("http: multiple registrations for " + pattern) } 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 } // Helpful behavior: // If pattern is /tree/, insert an implicit permanent redirect for /tree. // It can be overridden by an explicit registration. n := len(pattern) if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit { // If pattern contains a host name, strip it and use remaining // path for redirect. path := pattern if pattern[0] != '/' { // In pattern, at least the last character is a '/', so // strings.Index can't be -1. path = pattern[strings.Index(pattern, "/"):] } url := &url.URL{Path: path} mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(url.String(), StatusMovedPermanently), pattern: pattern} }}
这个ServeMux实体mux里面维护了一个map,这个map就是具体的pattern(路径)和调用方法的对于关系。定义如下
type ServeMux struct { mu sync.RWMutex m map[string]muxEntry hosts bool // whether any patterns contain hostnames}
当服务ListenAndServe启动监听后会阻塞等待:
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 } srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay) time.Sleep(tempDelay) continue } return e } tempDelay = 0 c := srv.newConn(rw) c.setState(c.rwc, StateNew) // before Serve can return go c.serve(ctx) }
当接收到一个请求后Accept获取请求内容,go c.serve(ctx)启动协程去处理,在这个方法里面先解析参数后调用ServeHTTP处理
w, err := c.readRequest(ctx)serverHandler{c.server}.ServeHTTP(w, w.req)
ServeHTTP进入
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { handler := sh.srv.Handler if handler == nil { handler = DefaultServeMux } if req.RequestURI == "*" && req.Method == "OPTIONS" { handler = globalOptionsHandler{} } handler.ServeHTTP(rw, req)}
接口定义如下:
type Handler interface { ServeHTTP(ResponseWriter, *Request)}
实现方式如下/usr/local/go/src/net/http/server.go:
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { if r.RequestURI == "*" { if r.ProtoAtLeast(1, 1) { w.Header().Set("Connection", "close") } w.WriteHeader(StatusBadRequest) return } h, _ := mux.Handler(r) h.ServeHTTP(w, r)}
这里面通过 mux.Handler获取handler,然后通过之前说的适配器模式ServeHTTP调用具体实现方法。
细节补充一下,怎么获取handler,这个和之前怎么注册相结合:
func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) { mux.mu.RLock() defer mux.mu.RUnlock() // Host-specific pattern takes precedence over generic ones if mux.hosts { h, pattern = mux.match(host + path) } if h == nil { h, pattern = mux.match(path) } if h == nil { h, pattern = NotFoundHandler(), "" } return}
这个从之前注册的map里面获取pattern的方法,那么我们就找到了服务怎样调用的了。
- go-restful实战与深入分析之基础篇
- go-restful实战与深入分析之使用篇
- go-restful实战与深入分析之源码篇
- Go语言RESTful API开发实战
- go-restful之hello world
- [ios开发基础之CoreData[4]]CoreData深入分析篇
- FFmpeg深入分析之零-基础
- FFmpeg深入分析之零-基础
- FFmpeg深入分析之零-基础
- FFmpeg深入分析之零-基础
- FFmpeg深入分析之零-基础
- FFmpeg深入分析之零-基础
- FFmpeg深入分析之零-基础
- FFmpeg深入分析之零-基础
- FFmpeg深入分析之零-基础
- FFmpeg深入分析之零-基础
- FFmpeg深入分析之零-基础
- FFmpeg深入分析之零-基础
- FreeRTOS临界段和开关中断
- Java基础知识之类加载器
- Python 第三方库 Twisted 安装与 Scrapy 安装
- 一张图看明白弹性的大数据架构
- jsp、freemarker、velocity区别
- go-restful实战与深入分析之基础篇
- 537. Complex Number Multiplication
- 112. Path Sum
- HDU 4405 Aeroplane chess(dp)
- JavaScript如何实现动态显示时间
- LaTex分行分段分页与项目列表
- css伪类
- 积分系统(4)-详细公告页面的“B”层跟“D”层
- 已知先序和中序构建二叉树并且以层序输出