go语言原生http库分析(1)
来源:互联网 发布:盘锦数控编程人才网 编辑:程序博客网 时间:2024/05/17 18:44
构建一个HTTP服务器的简单例子
package mainimport ("net/http")func SayHello(w http.ResponseWriter, req *http.Request) {w.Write([]byte("Hello"))}func main() {http.HandleFunc("/hello", SayHello)http.ListenAndServe(":8001", nil)}
当我们访问 地址IP:8001/hello 就会得到“hello”输出在浏览器上。
我们分析下这是怎么实现的。先看下接口函数ListenAndServe
func ListenAndServe(addr string, handler Handler) error {server := &Server{Addr: addr, Handler: handler}return server.ListenAndServe()}
实际上是生成一个Server对象,然后执行Server对象的函数ListenAndServe()。在分析ListenAndServe()之前我们先看下Handler,实际上Handler是个接口
type Handler interface {ServeHTTP(ResponseWriter, *Request)}
在看Request和ResponseWriter
描述请求头的Request
type Request struct {Method stringURL *url.URLProto string // "HTTP/1.0"ProtoMajor int // 1ProtoMinor int // 0Header HeaderBody io.ReadCloserContentLength int64TransferEncoding []stringClose boolHost stringForm url.ValuesPostForm url.ValuesMultipartForm *multipart.FormTrailer HeaderRemoteAddr stringRequestURI stringTLS *tls.ConnectionStateCancel <-chan struct{}}
描述应答的ResponseWriter
type ResponseWriter interface {// Header returns the header map that will be sent by// WriteHeader. Changing the header after a call to// WriteHeader (or Write) has no effect unless the modified// headers were declared as trailers by setting the// "Trailer" header before the call to WriteHeader (see example).// To suppress implicit response headers, set their value to nil.Header() Header// Write writes the data to the connection as part of an HTTP reply.// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)// before writing the data. If the Header does not contain a// Content-Type line, Write adds a Content-Type set to the result of passing// the initial 512 bytes of written data to DetectContentType.Write([]byte) (int, error)// WriteHeader sends an HTTP response header with status code.// If WriteHeader is not called explicitly, the first call to Write// will trigger an implicit WriteHeader(http.StatusOK).// Thus explicit calls to WriteHeader are mainly used to// send error codes.WriteHeader(int)}
现在我们回到Server类的ListenAndServe()函数
func (srv *Server) ListenAndServe() error {addr := srv.Addrif addr == "" {addr = ":http"}ln, err := net.Listen("tcp", addr)if err != nil {return err}return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})}
实际上这个函数只是执行TCP地址监听,然后执行Server函数,我们看下该函数干了什;函数头有解释,大概意思就是监听一个地址,然后接受连接,然后生成一个goroutine读取这个新的连接请求,而是调用handler去处理这个请求
// Serve accepts incoming connections on the Listener l, creating a// new service goroutine for each. The service goroutines read requests and// then call srv.Handler to reply to them.// Serve always returns a non-nil error.func (srv *Server) Serve(l net.Listener) error {defer l.Close()if fn := testHookServerServe; fn != nil {fn(srv, l)}var tempDelay time.Duration // how long to sleep on accept failureif err := srv.setupHTTP2(); err != nil {return err}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 = 0c := srv.newConn(rw)c.setState(c.rwc, StateNew) // before Serve can returngo c.serve()}}
handler是啥?我们一开始就说明了,实际上它是一个接口,具体怎么实现由客户定义。但是我们的例子中没有传入这样一个handler。那这个handler怎么来呢?我们继续分析,接受客户端连接后,执行
c := srv.newConn(rw)c.setState(c.rwc, StateNew) // before Serve can returngo c.serve()
生成一个连接对象,然后执行连接对象的函数server,我们接着分析该函数:
// Serve a new connection.func (c *conn) serve() {c.remoteAddr = c.rwc.RemoteAddr().String()defer func() {if err := recover(); err != nil {const size = 64 << 10buf := make([]byte, size)buf = buf[:runtime.Stack(buf, false)]c.server.logf("http: panic serving %v: %v\n%s", c.remoteAddr, err, buf)}if !c.hijacked() {c.close()c.setState(c.rwc, StateClosed)}}()if tlsConn, ok := c.rwc.(*tls.Conn); ok {if d := c.server.ReadTimeout; d != 0 {c.rwc.SetReadDeadline(time.Now().Add(d))}if d := c.server.WriteTimeout; d != 0 {c.rwc.SetWriteDeadline(time.Now().Add(d))}if err := tlsConn.Handshake(); err != nil {c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)return}c.tlsState = new(tls.ConnectionState)*c.tlsState = tlsConn.ConnectionState()if proto := c.tlsState.NegotiatedProtocol; validNPN(proto) {if fn := c.server.TLSNextProto[proto]; fn != nil {h := initNPNRequest{tlsConn, serverHandler{c.server}}fn(c.server, tlsConn, h)}return}}c.r = &connReader{r: c.rwc}c.bufr = newBufioReader(c.r)c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)for {w, err := c.readRequest()if c.r.remain != c.server.initialReadLimitSize() {// If we read any bytes off the wire, we're active.c.setState(c.rwc, StateActive)}if err != nil {if err == errTooLarge {// Their HTTP client may or may not be// able to read this if we're// responding to them and hanging up// while they're still writing their// request. Undefined behavior.io.WriteString(c.rwc, "HTTP/1.1 431 Request Header Fields Too Large\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n431 Request Header Fields Too Large")c.closeWriteAndWait()return}if err == io.EOF {return // don't reply}if neterr, ok := err.(net.Error); ok && neterr.Timeout() {return // don't reply}var publicErr stringif v, ok := err.(badRequestError); ok {publicErr = ": " + string(v)}io.WriteString(c.rwc, "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\n400 Bad Request"+publicErr)return}// Expect 100 Continue supportreq := w.reqif req.expectsContinue() {if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {// Wrap the Body reader with one that replies on the connectionreq.Body = &expectContinueReader{readCloser: req.Body, resp: w}}} else if req.Header.get("Expect") != "" {w.sendExpectationFailed()return}// HTTP cannot have multiple simultaneous active requests.[*]// Until the server replies to this request, it can't read another,// so we might as well run the handler in this goroutine.// [*] Not strictly true: HTTP pipelining. We could let them all process// in parallel even if their responses need to be serialized.serverHandler{c.server}.ServeHTTP(w, w.req)if c.hijacked() {return}w.finishRequest()if !w.shouldReuseConnection() {if w.requestBodyLimitHit || w.closedRequestBodyEarly() {c.closeWriteAndWait()}return}c.setState(c.rwc, StateIdle)}}
该函数开始尝试TLS握手,如果失败,超时则不是TLS连接,则直接读取http请求:
w, err := c.readRequest()
接着生成一个服务对象,执行服务对象的服务函数:
serverHandler{c.server}.ServeHTTP(w, w.req)
我们看下该函数:
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {handler := sh.srv.Handlerif handler == nil {handler = DefaultServeMux}if req.RequestURI == "*" && req.Method == "OPTIONS" {handler = globalOptionsHandler{}}handler.ServeHTTP(rw, req)}
意思很明显,如果handler为空,则赋值一个DefaultServeMux,也就是默认的Handler,然后执行该默认Handler的服务函数来处理请求:
handler.ServeHTTP(rw, req)
下篇我们将分析该默认Handler.
- go语言原生http库分析(1)
- go语言原生http库分析 (2)
- GO语言HTTP代理服务器
- go http分析
- Go语言分析
- go语言 通过http包搭建简单web服务器 对http包源码的略微分析
- Go语言net/http 解读.
- go语言的http包
- go 原生http web 服务跨域restful api 写法
- 【Go】原生http get和post请求框架
- Android 原生应用开发得到Go语言支持
- golang讲解(go语言)标准库分析之strings
- go web编程-原生库实现
- go语言学习 1-初识go语言
- GO 语言 http 服务端(简单实例)
- Go语言 简单的http服务器示例
- Go语言 如果实现http重连?
- Go语言Http Server源码阅读
- 博弈论基础知识: 巴什博奕+威佐夫博奕+尼姆博弈(及Staircase)
- 人生经验 一年多自学MATLAB的经验
- 50道编程小题目之【兔子数量】
- MPI接收任意源任意标志消息
- poj 1067 取石子游戏(威佐夫博弈模板)
- go语言原生http库分析(1)
- BUG-Redefine handleMessage()
- linux下压缩与解压(zip、unzip、tar)详解
- 数据库中基本概念
- LeetCode First Missing Positive
- 证书相关概念及使用openssl生成自认证证书
- 【cqbzoj】:1330 Prime DP(Ahio2001 质数和分解)
- ps钢笔工具/路径/钢笔抠图/字体工具
- css 浮动