浅析Go语言http服务handler对象底层原理

wuzhc · · 413 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

本文来源于: https://gobea.cn/blog/detail/15zqpwrq.html

最简单的http服务

对于golang来说,创建一个http服务是轻而易举的事情,如下,我们创建了一个非常简单的http服务,监听8899端口,只提供一个接口返回hello world

package main
import (
    "fmt"
    "net/http"
)
func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "hello world")
    })
    http.ListenAndServe(":8899", nil)
}

当你在游览器输入http://127.0.0.1:8899时,便能看到hello world的输出

http服务

对于golang的http服务,我们主要理解两个对象,:

  • Handler,它是请求的处理对象,Handler对象需要实现ServeHTTP方法,ServeHTTP执行的是我们的业务逻辑,一般我们定义的func(w http.ResponseWriter, r *http.Request)的方法需要经过http.HandlerFunc包装为Handler对象
  • ServeMux,它相当于一个路由注册器,保存的请求路径patternHandler对象的map表,通过pattern找到对应的Handler对象,然后执行Handler对象的ServeHTTP方法

简单的说,http的执行对象是handler,而要成为handler对象.则必须实现ServeHTTP方法,例如HandlerFunc实现了ServeHTTP方法,所以它也是一个handler对象

handler对象

// Handler接口
type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

// HandlerFunc实现了Handler接口
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

server从路由中找到handler对象,执行handler对象中的ServeHTTP方法,也就是说,要作为路由的Handler对象,需要实现ServeHTTP方法,有关handler如下:
https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e8dc81c24cd24cbe82069d2c1d60d38f~tplv-k3u1fbpfcp-zoom-1.image

  • handler函数,具有func(w http.ResponseWriter, r *http.Requests)签名的函数,需要经过HandlerFunc函数包装,否则不能作为路由的Handler对象,
  • handler处理函数,经过HandlerFunc结构包装的handler函数,HandlerFunc实现了ServeHTTP接口方法的函数
  • handler对象,实现了Handler接口ServeHTTP方法的结构

注册路由ServeMux

type ServeMux struct {
    mu    sync.RWMutex
    m     map[string]muxEntry
    hosts bool 
}

type muxEntry struct {
    explicit bool
    h        Handler
    pattern  string
}

// ServeMux也拥有ServeHTTP方法,也就说ServeMux实现了Handler接口,即ServeMuX其实也是一个Handler对象,不过ServeMux的ServeHTTP方法不是用来处理request和respone,而是用来找到路由注册的handler
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)
}

如上,ServeMux.m保存了路由规则pattern以及对应的Handler处理对象,另外ServeMux也拥有ServeHTTP方法,也就说ServeMux实现了Handler接口,即ServeMuX其实也是一个Handler对象,不过ServeMux的ServeHTTP方法不是用来处理request和respone,而是用来找到路由注册的handler

package main

import (
    "fmt"
    "net/http"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "hello world")
    })
    mux.HandleFunc("/test", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "hello world")
    })
    http.ListenAndServe(":8899", mux)
}

Server

http.ListenAndServe(":8899",mux)
// 等价于
serv := &http.Server{
        Addr:    ":8899",
        Handler: mux,
    }
serv.ListenAndServe()

http.ListenAndServe源码如下:

func ListenAndServe(addr string, handler Handler) error {
    server := &Server{Addr: addr, Handler: handler}
    return server.ListenAndServe()
}

来源

参考


有疑问加站长微信联系(非本文作者)

本文来自:Segmentfault

感谢作者:wuzhc

查看原文:浅析Go语言http服务handler对象底层原理

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

413 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传