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.






 

0 0
原创粉丝点击