千家信息网

golang构建HTTP服务的实现步骤是什么

发表于:2026-11-04 作者:千家信息网编辑
千家信息网最后更新 2026年11月04日,这篇文章给大家介绍golang构建HTTP服务的实现步骤是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。参考:一个go最简单的Http服务器程序package main im
千家信息网最后更新 2026年11月04日golang构建HTTP服务的实现步骤是什么

这篇文章给大家介绍golang构建HTTP服务的实现步骤是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

  • 参考:

一个go最简单的Http服务器程序

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

HTTP

除去细节,理解HTTP构建的网络应用只要关注两个端--客户端(client)和服务端(server),两个端的交互来自client的request,以及server端的response。所谓的http服务器,主要在于如何接受client的request,并向client返回response。

接收request的过程中,最重要的莫过于路由(router),即实现一个Multiplexer器。Go中既可以使用内置的mutilplexer--DefaultServeMux,也可以自定义。Multiplexer路由的目的就是为了找到处理器函数(hander),后者将对request进行处理,同时构建response。

简单总结就是这个流程:

因此,理解go中的http服务,,最重要的就是要理解Multiplexer和hander,Golang中的Multiplexer基于ServerMux结构,同时也实现了Handler接口。

·hander函数:具有func(w http.ResponseWriter, r *http.Requests)签名的函数

·handler处理器(函数):经过HanderFunc结构包装的handler函数,它实现了ServeHTTP接口方法的函数。调用handler处理器的ServeHTTP方法时,即调用handler函数本身。

·handler对象:实现了Hander接口ServeHTTP方法的结构。

Golang的http处理流程可以用下面一张图表示,后面内容是针对图进行说明:

Handler

Golang没有继承,类多态的方法可以通过接口实现。所谓接口则是定义声明了函数签名,任何结构只要实现了与接口函数签名相同的方法,就等同于实现了接口。go的http服务都是基于handler进行处理的。

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

任何结构体,只要实现了ServeHTTP方法,这个结构就可以称之为handler对象。ServeMux会使用handler并调用其ServeHTTP方法处理请求并返回响应。

ServeMux

了解了Handler之后,再看ServeMux。ServeMux源码很简单:

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

ServeMux结构中最重要的字段为m,这是一个map,key是一些url模式,value是一个muxEntry结构,后者里定义存储了具体的url模式和handler。

当然,所谓的ServeMux也实现了ServeHTTP接口,也算是一个handler,不过ServeMux的ServeHTTP方法不是用来处理request和respone,而是用来找到路由注册的handler。

Server

除了ServeMux和Handler,还有一个结构Server需要了解。从http.ListenAndServe的源码可以看出,它创建了一个server对象,并调用server对象的ListenAndServe方法:

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

查看server的结构如下:

type Server struct {    Addr         string            Handler      Handler           ReadTimeout  time.Duration     WriteTimeout time.Duration     TLSConfig    *tls.Config        MaxHeaderBytes int     TLSNextProto map[string]func(*Server, *tls.Conn, Handler)     ConnState func(net.Conn, ConnState)    ErrorLog *log.Logger    disableKeepAlives int32     nextProtoOnce     sync.Once     nextProtoErr      error     }

server结构存储了服务器处理请求常见的字段。其中Handler字段也保留Hander接口。如果Server接口没有提供Handler结构对象,那么会使用DefaultServeMux做Multiplexer。

创建HTTP服务

创建一个http服务,大致需要经历两个过程,首先需要注册路由,即提供url模式和handler函数的映射,其次就是实例化一个server对象,并开启对客户端的监听。

http.HandleFunc("/", indexHandler)
http.ListenAndServe("127.0.0.1:8000", nil) 或者: server := &Server{Addr: addr, Handler: handler} server.ListenAndServe()

http注册路由

net/http包暴露的注册路由的api很简单,http.HandleFunc选取了DefaultServeMux作为multiplexer:

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {    DefaultServeMux.HandleFunc(pattern, handler)}

实际上,DefaultServeMux是ServeMux的一个实例。当然http包也提供了NewServeMux方法创建一个ServeMux实例,默认则创建一个DefaultServeMux:

// NewServeMux allocates and returns a new ServeMux.func NewServeMux() *ServeMux {    return new(ServeMux)} // DefaultServeMux is the default ServeMux used by Serve.var DefaultServeMux = &defaultServeMux var defaultServeMux ServeMux

注意,go创建实例的过程中,也可以使用指针方式,即

   type Server struct{}   server := Server{}

和下面的一样都可以创建Server的实例

 var DefaultServer Server  var server = &DefalutServer

因此DefaultServeMux的HandleFunc(pattern,handler)方法实际是定义在ServeMux下的:

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {    mux.Handle(pattern, HandlerFunc(handler))}

上述代码中,HandlerFunc是一个函数类型。同时实现了Handler接口的ServeHTTP方法。使用HandlerFunc类型包装一下路由定义的indexHandler函数,其目的就是为了让这个函数也实现ServeHTTP方法,即转变成一个handler处理器(函数)。

type HandlerFunc func(ResponseWriter, *Request) func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {    f(w, r)}

一旦这样做了,就意味着我们的indexHandler函数也有了ServeHTTP方法。
此外,ServeMux的Handle方法,将会对pattern和handler函数做一个map映射:

func (mux *ServeMux) Handle(pattern string, handler Handler) {    mux.mu.Lock()    defer mux.mu.Unlock()     if pattern == "" {        panic("http: invalid pattern " + pattern)    }    if handler == nil {        panic("http: nil handler")    }    if mux.m[pattern].explicit {        panic("http: multiple registrations for " + pattern)    }     if mux.m == nil {        mux.m = make(map[string]muxEntry)    }    mux.m[pattern] = muxEntry{explicit: true, h: handler, pattern: pattern}     if pattern[0] != '/' {        mux.hosts = true    }     n := len(pattern)    if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit {         path := pattern        if pattern[0] != '/' {            path = pattern[strings.Index(pattern, "/"):]        }        url := &url.URL{Path: path}        mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(url.String(), StatusMovedPermanently), pattern: pattern}    }}

由此可见,Handle函数的主要目的在于把handler和pattern模式绑定到map[string]muxEntry的map上,其中muxEntry保存了更多pattern和handler的信息。Server的m字段就是map[string]muxEntry这样一个map。
此时,pattern和handler的路由注册完成。

开启监听

注册好路由之后,启动web服务还需要开启服务器监听。http的ListenAndServer方法中可以看到创建了一个Server对象,并调用了Server对象的同名方法:

func ListenAndServe(addr string, handler Handler) error {    server := &Server{Addr: addr, Handler: handler}    return server.ListenAndServe()} func (srv Server) ListenAndServe() error {    addr := srv.Addr    if addr == "" {        addr = ":http"    }    ln, err := net.Listen("tcp", addr)    if err != nil {        return err    }    return srv.Serve(tcpKeepAliveListener{ln.(net.TCPListener)})}

Server的ListenAndServer方法中,会初始化监听地址Addr,同时调用Listen方法设置监听。最后将监听的TCP对象传入Serve方法:

func (srv *Server) Serve(l net.Listener) error {    defer l.Close()    ...     baseCtx := context.Background()    ctx := context.WithValue(baseCtx, ServerContextKey, srv)    ctx = context.WithValue(ctx, LocalAddrContextKey, l.Addr())    for {        rw, e := l.Accept()        ...        c := srv.newConn(rw)        c.setState(c.rwc, StateNew) // before Serve can return        go c.serve(ctx)    }}

处理请求

监听开启之后,一旦客户端请求到底,go就开启一个协程处理请求,主要逻辑都在server方法之中。

serve方法比较长,其主要职能就是,创建一个上下文对象,然后调用Listener的Accept方法用来获取连接数据并使用newConn方法创建连接对象。最后使用goroutein协程的方式处理连接请求。因此每一个连接都开启了一个协程,请求的上下文都不同,同时又保证了go的高并发。serve也是一个长长的方法:

func (c *conn) serve(ctx context.Context) {    c.remoteAddr = c.rwc.RemoteAddr().String()    defer func() {        if err := recover(); err != nil {            const size = 64 << 10            buf := 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)        }    }()     ...     for {        w, err := c.readRequest(ctx)        if c.r.remain != c.server.initialReadLimitSize() {            // If we read any bytes off the wire, we're active.            c.setState(c.rwc, StateActive)        }        ...                }                ...            serverHandler{c.server}.ServeHTTP(w, w.req)        w.cancelCtx()        if c.hijacked() {            return        }        w.finishRequest()        if !w.shouldReuseConnection() {            if w.requestBodyLimitHit || w.closedRequestBodyEarly() {                c.closeWriteAndWait()            }            return        }        c.setState(c.rwc, StateIdle)    }}

尽管serve很长,里面的结构和逻辑还是很清晰的,使用defer定义了函数退出时,连接关闭相关的处理。然后就是读取连接的网络数据,并处理读取完毕时候的状态。接下来就是调用serverHandler{c.server}.ServeHTTP(w,w.req)方法处理请求了。最后就是请求处理完毕的逻辑。serverHandler是一个重要的结构,它仅有一个字段,即Server结构,同时它也实现了Hander接口方法ServeHTTP,同时它也实现了Handler接口方法ServeHTTP,并在该接口方法中做了一个重要的事情,初始化multiplexer路由多路复用器。如果server对象没有制定Handler,则使用默认的DefaultServeMux作为路由Multiplexer。并调用初始化Handler的ServeHTTP方法。

type serverHandler struct {    srv *Server} func (sh serverHandler) ServeHTTP(rw ResponseWriter, req Request) {    handler := sh.srv.Handler    if handler == nil {        handler = DefaultServeMux    }    if req.RequestURI == "" && req.Method == "OPTIONS" {        handler = globalOptionsHandler{}    }    handler.ServeHTTP(rw, req)}

这里DefaultServeMux的ServeHTTP方法其实也是定义在ServeMux结构中的,相关代码如下:

func (mux *ServeMux) (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)} func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {    if r.Method != "CONNECT" {        if p := cleanPath(r.URL.Path); p != r.URL.Path {            _, pattern = mux.handler(r.Host, p)            url := *r.URL            url.Path = p            return RedirectHandler(url.String(), StatusMovedPermanently), pattern        }    }    return mux.handler(r.Host, r.URL.Path)} func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {    mux.mu.RLock()    defer mux.mu.RUnlock()     // Host-specific pattern takes precedence over generic ones    if mux.hosts {        h, pattern = mux.match(host + path)    }    if h == nil {        h, pattern = mux.match(path)    }    if h == nil {        h, pattern = NotFoundHandler(), ""    }    return} func (mux *ServeMux) match(path string) (h Handler, pattern string) {    var n = 0    for k, v := range mux.m {        if !pathMatch(k, path) {        continue    }    if h == nil || len(k) > n {        n = len(k)        h = v.h        pattern = v.pattern        }    }    return}

mux的ServeHTTP方法通过调用其Handler方法寻找注册到路由上的handler函数,并调用该函数的ServeHTTP方法。

mux的Handler方法对URL简单的处理,然后调用handler方法,后者会创建一个锁,同时调用match方法返回一个handler和pattern。
在match方法中,mux的m字段是map[string]muxEntry,后者存储了pattern和handler处理器函数,因此通过迭代m寻找出注册路由的pattern模式与实际url匹配的handler函数并返回。
返回的结构一直传递到mux的ServeHTTP方法,接下来调用handler函数的ServeHTTP方法,即IndexHandler函数,然后把reponse写到http.RequestWirter对象返回给客户端。

上述函数运行结束即serverHandler{c.server}.ServeHTTP(w, w.req)运行结束。接下来就是对请求处理完毕之后上希望和连接断开的相关逻辑。

至此,Golang中一个完整的http服务介绍完毕,包括注册路由,开启监听,处理连接,路由处理函数。

关于golang构建HTTP服务的实现步骤是什么就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

方法 函数 处理 结构 路由 接口 服务 对象 就是 同时 监听 字段 重要 处理器 实例 模式 客户 服务器 逻辑 接下来 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技园 伟宏互联网科技 科技互联网项目 安徽鑫晟辉互联网科技 互联网科技公司有哪些 左右互联网络科技 深圳卡尔迅互联网科技有限公司怎么样 互联网 科技馆 银川新华互联网科技职业技术培训学校图片 福建科技产业互联网发展 世界互联网科技公司市值排名 阿大互联网科技有限公司 互联网科技大奖都有哪些公司 互联网科技创新的路径 互联网企业科技类企业如何做账 广东工业互联网大赛深圳学泰科技 宁波跨境商互联网科技有限公司 易租星互联网科技有限公司 三亚科技创新互联网基地 互联网金融金融科技 互联网下的科技发展 重庆互联网络科技 互联网与未来科技 宜安科技 互联网金融 互联网高科技股票 互联网实体化科技化 互联网金融科技展 合肥互联网科技公司公章图片 2021世界互联网领先科技成果发布 中国主要互联网科技公司
0