陈银波的知识小站

  • 首页
  • 数学
  • 算法
  • 图
  • 数据
  • 记忆
复杂 = f (简单1, 简单2, ... , 简单n)
  1. 首页
  2. 工程
  3. 正文

Go:net/http 服务端底层设计简述

1 9 月, 2024 735点热度 2人点赞 6条评论

0 前言

我自己使用 Go 语言进行项目开发已经有一年多的时间,不过一直很少去了解 Go 语言相关的底层设计的一些东西。最近花时间去看了 net/http 的底层设计的一些东西,这篇文章就是把我觉得 net/http 最有价值、最需要了解的东西拿出来分享。

1 从使用 net/http 的使用方式出发

使用 net/http 启动一个服务非常简单:

package main

import (
	"io"
	"log"
	"net/http"
)

func main() {
	// Hello world, the web server

	helloHandler := func(w http.ResponseWriter, req *http.Request) {
		io.WriteString(w, "Hello, world!\n")
	}

	http.HandleFunc("/", helloHandler)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

上面这段代码有三个核心。

定义处理器函数

	helloHandler := func(w http.ResponseWriter, req *http.Request) {
		io.WriteString(w, "Hello, world!\n")
	}

这里定义了一个匿名函数 helloHandler,它接受两个参数:

  • w http.ResponseWriter: 这是一个用于构造 HTTP 响应的接口对象。我们可以使用它来向客户端发送数据。
  • req *http.Request: 这是一个包含 HTTP 请求所有信息的结构体。

io.WriteString 方法用来向 http.ResponseWriter 写入字符串 "Hello, world!\n",客户端接收 http.ResponseWriter 中的内容。

注册处理器

http.HandleFunc("/", helloHandler)

http.HandleFunc 用来注册处理器函数。第一个参数是路径模式,这里我们指定为根路径 /,这意味着对于所有发往服务器根路径的请求都将由 helloHandler 处理。

启动服务器

log.Fatal(http.ListenAndServe(":8080", nil))

http.ListenAndServe 方法用来启动 HTTP 服务器,监听并服务于指定的网络地址。这里我们让服务器监听本地机器上的 8080 端口。函数的第二个参数是处理器,当该参数为 nil 时,默认使用 http.DefaultServeMux。

2 http.ListenAndServe

我们当然选择从最关键的启动服务 http.ListenAndServe 入手,看看启动服务这个过程具体是做了什么。

  • 监听地址:当 http.ListenAndServe 启动后,它会在指定的地址上创建一个监听套接字(socket),等待客户端的连接请求。
  • 接受连接:每当有一个新的连接请求到达时,ListenAndServe 会接受这个连接,并为每个连接创建一个新的 goroutine。(一个连接一个 goroutine)
  • 读取请求:在每个新创建的 goroutine 中,服务器会读取客户端发送过来的 HTTP 请求。请求中包含了客户端想要访问的 URL、请求方法(如 GET、POST 等)以及其他相关信息。(每个连接可能有多个 HTTP 请求)
  • 请求分发:一旦请求被完全读取,服务器会将请求传递给多路复用器进行分发。(多路复用器可以基于请求的 URL 路径来决定哪个处理器应该处理这个请求)
  • 请求处理:多路复用器查找与请求 URL 匹配的处理器,并调用这个处理器来处理请求。
  • 发送响应:处理函数完成请求处理后,向客户端发送响应。响应可以包括状态码、响应头和响应体等部分。

上面流程就是 http.ListenAndServe 具体在做的事情。我刻意回避了一些底层的关键模块名如多路复用器 http.ServeMux,原因是希望你们对基本流程有所了解,然后再深入细节。

3 http.ServeMux 多路复用器

前面我们了解了 http.ListenAndServe 的具体流程,这里面涉及到非常重要的一点就是,请求的分发和处理,不同的路由使用不同的处理器进行处理。

在我们实际使用 net/http 进行开发的时候,什么样的路由如何进行对应的处理,这是我们自己决定和编写的,这是我们在进行 web 开发中非常重要的一步。因此,下面我们来了解 net/http 是如何对我们的路由和处理进行管理的。

http.ServeMux 的内部维护了一个路由表,它存储了所有注册的处理器。路由表是由一组键值对组成的,其中键是 URL 路径模式,值是对应的处理器。当一个 HTTP 请求到达时,ServeMux 会使用其内部的路由表来查找与请求 URL 匹配的处理器。

注册处理器主要有两种方式:

  • 使用 http.HandleFunc:

    http.HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
    
  • 这个函数会将给定的处理函数注册到默认的 http.ServeMux 上。pattern 是一个 URL 路径模式,handler 是一个处理函数。

  • 使用 http.ServeMux.Handle:

    func (mux *ServeMux) Handle(pattern string, handler Handler)
    

    这个方法允许你将任意实现了 http.Handler 接口的对象注册到一个具体的 ServeMux 实例上。而 http.Handler 接口对象需要实现的函数是 func(http.ResponseWriter, *http.Request)

可以看到,无论是 处理函数 还是 处理器,其核心都是函数 func(http.ResponseWriter, *http.Request)。

所以:

  • 如果你有一个处理函数 func(http.ResponseWriter, *http.Request),可以直接使用 http.HandleFunc 进行注册。
  • 同样,你也可以把处理函数 func(http.ResponseWriter, *http.Request) 包装进 http.Handler,然后使用 func (mux *ServeMux) Handle(pattern string, handler Handler) 进行注册。

4 总结

以上即为我关于 Go net/http 的简单分享,实际简单使用 net/http 时,就是简单两步:

  • 准备路由和处理函数 func(ResponseWriter, *Request),进行注册
  • 调用 http.ListenAndServe 完成服务的启动

谢谢大家。

标签: 暂无
最后更新:1 9 月, 2024

陈银波

邮箱:agwave@foxmail.com 知乎:https://www.zhihu.com/people/agwave github:https://github.com/agwave leetcode:https://leetcode.cn/u/agwave

点赞
下一篇 >

文章评论

  • American Football Stream online

    Do you mind if I quote a few of your posts as long as I provide credit and sources back to your weblog? My blog is in the very same niche as yours and my users would really benefit from some of the information you provide here. Please let me know if this okay with you. Thanks a lot!

    9 9 月, 2025
    回复
  • Live Basketball Streaming

    Fantastic site you have here but I was curious if you knew of any discussion boards that cover the same topics talked about here? I'd really love to be a part of community where I can get opinions from other experienced individuals that share the same interest. If you have any suggestions, please let me know. Appreciate it!

    9 9 月, 2025
    回复
  • Free Baseball Streaming Website

    I really like your writing style, excellent information, appreciate it for putting up :D. "God save me from my friends. I can protect myself from my enemies." by Claude Louis Hector de Villars.

    10 9 月, 2025
    回复
  • jili

    Great post. I am facing a couple of these problems.

    11 9 月, 2025
    回复
  • my blog

    Do you have a spam issue on this website; I also am a blogger, and I was wanting to know your situation; we have developed some nice methods and we are looking to exchange methods with others, be sure to shoot me an email if interested.

    11 9 月, 2025
    回复
  • tlovertonet

    Howdy, i read your blog from time to time and i own a similar one and i was just curious if you get a lot of spam feedback? If so how do you stop it, any plugin or anything you can suggest? I get so much lately it's driving me insane so any help is very much appreciated.

    15 9 月, 2025
    回复
  • razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
    回复 Free Baseball Streaming Website 取消回复

    文章目录
    • 0 前言
    • 1 从使用 net/http 的使用方式出发
    • 2 http.ListenAndServe
    • 3 http.ServeMux 多路复用器
    • 4 总结
    分类
    • 图
    • 工程
    • 数学
    • 数据
    • 算法
    • 记忆
    最新 热点 随机
    最新 热点 随机
    你的重复性工作,我帮你自动化 “沙滩之城” Change Data Capture (CDC) 技术初探 IPv6在物联网中的应用 IPv6首部的改进:简化与优化网络通信
    IPv6在物联网中的应用IPv6首部的改进:简化与优化网络通信IPv6:下一代互联网协议Change Data Capture (CDC) 技术初探“沙滩之城”
    一笔画问题揭秘:轻松掌握欧拉图与欧拉回路的奥秘 IPv6首部的改进:简化与优化网络通信 简单直观地理解神经网络 你的重复性工作,我帮你自动化 IPv6:下一代互联网协议
    归档
    • 2025 年 9 月
    • 2024 年 10 月
    • 2024 年 9 月
    • 2024 年 8 月
    • 2024 年 7 月
    • 2024 年 6 月
    • 2024 年 5 月

    COPYRIGHT © 2024 陈银波的知识小站. ALL RIGHTS RESERVED.

    Theme Kratos Made By Seaton Jiang

    粤ICP备2024254302号-1

    粤公网安备44030002003798号