hello world
package main
import (
"log"
"net/http"
)
func main() {
http.HandleFunc("/v1/hello", func(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("hello http\n"))
})
log.Fatal(http.ListenAndServe(":8090",nil))
}
启动当前服务
curl -X GET 'http://localhost:8090/v1/hello'
hello http
ServeHTTP
type BaseHander struct {
}
func (hander *BaseHander)ServeHTTP(resp http.ResponseWriter,req *http.Request){
fmt.Println("url path=>",req.URL.Path)
fmt.Println("url param a =>",req.URL.Query().Get("a"))
resp.Write([]byte("hello world"))
}
func main() {
http.ListenAndServe(":8080",&BaseHander{});
}
muxHandler 路由
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
es []muxEntry // slice of entries sorted from longest to shortest.
hosts bool // whether any patterns contain hostnames
}
type muxEntry struct {
h Handler
pattern string
}
type Handler interface {
ServeHTTP(ResponseWriter, *Request) // 路由实现器
}
Handler是一个接口,但是前一小节中的sayhelloName函数并没有实现ServeHTTP这个接口,为什么能添加呢?原来在http包里面还定义了一个类型HandlerFunc,我们定义的函数sayhelloName就是这个HandlerFunc调用之后的结果,这个类型默认就实现了ServeHTTP这个接口,即我们调用了HandlerFunc(f),强制类型转换f成为HandlerFunc类型,这样f就拥有了ServeHTTP方法。
package mux
import (
"net/http"
)
type muxHandler struct {
handlers map[string]http.Handler
handleFuncs map[string]func(resp http.ResponseWriter, req *http.Request)
}
func NewMuxHandler() *muxHandler {
return &muxHandler{
make(map[string]http.Handler),
make(map[string]func(resp http.ResponseWriter, req *http.Request)),
}
}
func (handler *muxHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
urlPath := req.URL.Path
if hl, ok := handler.handlers[urlPath]; ok {
hl.ServeHTTP(resp, req)
return
}
if fn, ok := handler.handleFuncs[urlPath]; ok {
fn(resp, req)
return
}
http.NotFound(resp, req)
}
func (hander *muxHandler) Handle(pattern string, hl http.Handler) {
hander.handlers[pattern] = hl
}
func (handler *muxHandler) HandleFunc(pattern string, fn func(resp http.ResponseWriter, req *http.Request)) {
handler.handleFuncs[pattern] = fn
}
var (
port string
)
func main() {
flag.StringVar(&port, "port", ":8080", "port to listen")
flag.Parse()
router :=mux.NewMuxHandler()
router.Handle("/hello/golang/", &BaseHander{})
router.HandleFunc("/hello/world", func(resp http.ResponseWriter, req *http.Request) {
resp.Write([]byte("hello world"))
})
http.ListenAndServe(port, router)
}
go web的请求流程
go10.1的源码
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 failure
if err := srv.setupHTTP2_Serve(); err != nil {
return err
}
srv.trackListener(l, true)
defer srv.trackListener(l, false)
baseCtx := context.Background() // base is always background, per Issue 16220
ctx := context.WithValue(baseCtx, ServerContextKey, srv)
for {
rw, e := l.Accept()
if e != nil {
select {
case <-srv.getDoneChan():
return ErrServerClosed
default:
}
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)
}
}
go c.serve()这里我们可以看到客户端的每次请求都会创建一个Conn,这个Conn里面保存了该次请求的信息,然后再传递到对应的handler,该handler中便可以读取到相应的header信息,这样保证了每个请求的独立性。
参考
https://github.com/ma6174/blog/issues/11
https://www.cnblogs.com/itbsl/p/12175645.html