golang的http服务包 , 包括服务端和客户端
package main
import (
"net/http"
"fmt"
)
func HandConn(w http.ResponseWriter, r *http.Request) {
fmt.Println(r.Host)
fmt.Println(r.Method)
fmt.Println(r.URL)
w.Write([]byte("hello go"))
}
func main() {
// 注册处理函数
http.HandleFunc("/", HandConn)
// 启动
http.ListenAndServe(":8080", nil)
}
这样就创建了一个http的Server. 真简单呢.
- 服务启动
// ListenAndServe always returns a non-nil error.
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler} // 这个 handler 是用来处理 connections 的
return server.ListenAndServe()
}
- 建立连接之后再goroutine里处理
// go c.serve(ctx)
// Serve a new connection.
func (c *conn) serve(ctx context.Context) {
c.remoteAddr = c.rwc.RemoteAddr().String() // 远程地址.
ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr()) // 本地地址
defer func() {...}() //先不看这个
if tlsConn, ok := c.rwc.(*tls.Conn); ok {...} // 先过滤https的请求? 还是http2的请求.?
// HTTP/1.x from here on.
ctx, cancelCtx := context.WithCancel(ctx)
c.cancelCtx = cancelCtx // 塞入取消方法. 参考 context.
defer cancelCtx()
c.r = &connReader{conn: c}
c.bufr = newBufioReader(c.r) // 初始化读buf
c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10) // 初始化写buf
//// 大大的死循环.
for {
w, err := c.readRequest(ctx) // 读... req, err := readRequest(c.bufr, keepHostHeader)
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 {...} // 读出失败的处理
// Expect 100 Continue support
req := w.req
if req.expectsContinue() {
if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {
// Wrap the Body reader with one that replies on the connection
req.Body = &expectContinueReader{readCloser: req.Body, resp: w}
}
} else if req.Header.get("Expect") != "" {
w.sendExpectationFailed()
return
}
c.curReq.Store(w) // 把req存起来.
if requestBodyRemains(req.Body) {
registerOnHitEOF(req.Body, w.conn.r.startBackgroundRead)
} else {
w.conn.r.startBackgroundRead()
}
// 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.
// But we're not going to implement HTTP pipelining because it
// was never deployed in the wild and the answer is HTTP/2.
serverHandler{c.server}.ServeHTTP(w, w.req) // 处理... DefaultServeMux
w.cancelCtx() // 关闭刚刚的协程.
if c.hijacked() {
return
}
w.finishRequest()
if !w.shouldReuseConnection() {
if w.requestBodyLimitHit || w.closedRequestBodyEarly() {
c.closeWriteAndWait()
}
return
}
c.setState(c.rwc, StateIdle) // 再次改变状态 ... 到空闲.
c.curReq.Store((*response)(nil))
if !w.conn.server.doKeepAlives() {
// We're in shutdown mode. We might've replied
// to the user without "Connection: close" and
// they might think they can send another
// request, but such is life with HTTP/1.1.
return
}
if d := c.server.idleTimeout(); d != 0 { // 如果设置了空闲时间则. 等待.
c.rwc.SetReadDeadline(time.Now().Add(d))
if _, err := c.bufr.Peek(4); err != nil {
return
}
}
c.rwc.SetReadDeadline(time.Time{}) // 设置了读的结束时间.
}
}
默认的处理器.
// DefaultServeMux is the default ServeMux used by Serve.
// var DefaultServeMux = &defaultServeMux
// ServeHTTP dispatches the request to the handler whose
// pattern most closely matches the request URL.
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) // 其实是执行了 Handler // 根据host得到匹配的 h.
h.ServeHTTP(w, r)
}
echo框架的核心就是替换了 Handle 不在使用默认的 Handle ... 进而有了自己的路由规则.
网友评论