Go标准库net/http包的实现

 更新时间:2026年03月16日 10:08:11   作者:我叫黑大帅  
net/http是Go官方自带的 HTTP 框架,不用装任何第三方库,本文就来详细的介绍一下Go标准库net/http包的实现,感兴趣的可以了解一下

net/http 是 Go 官方自带的 HTTP 框架,不用装任何第三方库,直接就能写:

  • HTTP 服务端(写接口、网站、API)
  • HTTP 客户端(发请求、调用别人接口)

服务端

核心 API

  • http.HandleFunc(pattern, handler): 注册路由(将路径和对应的函数绑定)。
  • http.ListenAndServe(addr, handler): 启动监听并服务。「多客户端连接不阻塞」的核心!
  • http.ResponseWriter: 用于向客户端写入响应(写回数据)。
  • *http.Request: 包含客户端发来的所有信息(URL、Header、参数等)。
package main

import (
	"fmt"
	"net/http"
)

func helloHandler(w http.ResponseWriter, r *http.Request) {
	// r.Method 可以判断是 GET 还是 POST
	fmt.Fprintf(w, "你好,你访问的路径是: %s", r.URL.Path)
}

func main() {
	// 1. 路由注册
	http.HandleFunc("/", helloHandler)

	// 2. 启动服务,监听 8080 端口
	fmt.Println("服务器启动在 http://localhost:8080")
	err := http.ListenAndServe(":8080", nil)
	if err != nil {
		panic(err)
	}
}

HandleFunc与接口函数

// `net/http` 定义了一个接口
type Handler interface {
    ServeHTTP(w http.ResponseWriter, r *http.Request)
}


func(w http.ResponseWriter, r *http.Request)
w http.ResponseWriter 给客户端返回数据(写响应)
w.Write([]byte("返回内容"))
w.WriteHeader(404) // 设置状态码
fmt.Fprintln(w, "hello") // 也可以这样写
r *http.Request 获取客户端传过来的东西
  • URL 参数
  • POST 表单 / JSON
  • 请求头
  • 请求方法(GET/POST)

常用的 5 种HandleFunc用法

处理 GET 请求(获取 URL 参数)

http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
	// 获取 ?name=xxx & age=xxx
	name := r.URL.Query().Get("name")
	age := r.URL.Query().Get("age")

	w.Write([]byte("名字:" + name + " 年龄:" + age))
})

处理 POST 表单(前端提交数据)

http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
	// 解析 POST 表单
	r.ParseForm()

	// 获取表单参数
	username := r.PostForm.Get("username")
	password := r.PostForm.Get("password")

	w.Write([]byte("用户名:" + username + " 密码:" + password))
})

返回 JSON(写 API 接口)

type User struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

http.HandleFunc("/json", func(w http.ResponseWriter, r *http.Request) {
	user := User{Name: "张三", Age: 20}

	// 设置返回格式 JSON
	w.Header().Set("Content-Type", "application/json")

	// 编码并返回
	json.NewEncoder(w).Encode(user)
})

路由分组 / 多个接口

// 首页
http.HandleFunc("/", homeHandler)

// 用户相关
http.HandleFunc("/user/list", userListHandler)
http.HandleFunc("/user/info", userInfoHandler)

// 登录
http.HandleFunc("/login", loginHandler)

访问静态文件服务

// 访问 /static/ 下的文件 
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

ServeMux 与自定义 Handler

mux := http.NewServeMux()
mux.HandleFunc("/user", userHandler)
// 将 mux 传入 ListenAndServe
http.ListenAndServe(":8080", mux)

直接使用 http.HandleFunc (默认模式)

当你直接调用 http.HandleFunc 时,Go 会在后台使用一个全局默认的实例,叫 DefaultServeMux

  • 优点:代码少,写个小脚本测试非常快。
  • 缺点:它是全局共享的。如果你引入的第三方库也偷偷在 DefaultServeMux 上注册了路由,可能会产生冲突。此外,在单元测试中,全局变量会让测试变得互相干扰。

使用 http.NewServeMux() (自定义模式)

当你创建自己的 mux 时,你是在创建一个隔离的路由表

  • 优点:更安全、更灵活。你可以创建多个 mux,分别跑在不同的端口上,或者在测试时轻松地替换它。
package main

import (
	"fmt"
	"net/http"
)

func main() {
	// --- 局部变量 1:给普通用户的路由 ---
	userMux := http.NewServeMux()
	userMux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "这是【普通用户】的个人中心")
	})

	// --- 局部变量 2:给管理员的路由 ---
	adminMux := http.NewServeMux()
	adminMux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "这是【管理员】的用户管理界面")
	})

	// 在 8080 端口启动用户服务
	go http.ListenAndServe(":8080", userMux)

	// 在 9090 端口启动管理服务
	fmt.Println("服务已启动:8080 为用户,9090 为管理")
	http.ListenAndServe(":9090", adminMux)
}

客户端

常用 API

  • http.Get(url): 发送简单的 GET 请求。
  • http.Post(url, contentType, body): 发送 POST 请求。
  • http.Client: 如果需要设置超时、Header 等高级操作,需要自定义 Client。
resp, err := http.Get("https://api.github.com")
if err != nil {
    log.Fatal(err)
}
// 记得关闭 Body,防止内存泄漏
defer resp.Body.Close()

// 读取响应内容
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))

到此这篇关于Go标准库net/http包的实现的文章就介绍到这了,更多相关Go标准库net/http包内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • grpc-go如何通过context传递额外数据

    grpc-go如何通过context传递额外数据

    metadata是grpc内置的,用RPC服务传递http头数据,分in和out两种,对应的key都为一个空struct,这篇文章主要介绍了grpc-go通过context传递额外数据,需要的朋友可以参考下
    2024-02-02
  • Go语言状态机的实现

    Go语言状态机的实现

    本文主要介绍了Go语言状态机的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • 详解在Go语言单元测试中如何解决Redis存储依赖问题

    详解在Go语言单元测试中如何解决Redis存储依赖问题

    在编写单元测试时,除了 MySQL 这个外部存储依赖,Redis 应该是另一个最为常见的外部存储依赖了,本文就来讲解下如何解决 Redis 外部依赖,文章通过代码示例介绍的非常详细,需要的朋友可以参考下
    2023-08-08
  • golang等待触发事件的实例

    golang等待触发事件的实例

    这篇文章主要介绍了golang等待触发事件的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • golang中time包之时间间隔格式化和秒、毫秒、纳秒等时间戳格式输出的方法实例

    golang中time包之时间间隔格式化和秒、毫秒、纳秒等时间戳格式输出的方法实例

    时间和日期是我们编程中经常会用到的,下面这篇文章主要给大家介绍了关于golang中time包之时间间隔格式化和秒、毫秒、纳秒等时间戳格式输出的方法实例,需要的朋友可以参考下
    2022-08-08
  • go进行http请求偶发EOF问题分析

    go进行http请求偶发EOF问题分析

    go使用连接池进行http请求,一般都能请求成功,但偶然会出现请求失败返回EOF错误的情况,本文主要来带大家分析一下为什么会出现这样的问题并提供解决方法,需要的可以参考下
    2025-01-01
  • Golang 实现分片读取http超大文件流和并发控制

    Golang 实现分片读取http超大文件流和并发控制

    这篇文章主要介绍了Golang 实现分片读取http超大文件流和并发控制,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • golang fmt占位符的使用详解

    golang fmt占位符的使用详解

    这篇文章主要介绍了golang fmt占位符的使用详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • Golang 获取文件md5校验的方法以及效率对比

    Golang 获取文件md5校验的方法以及效率对比

    这篇文章主要介绍了Golang 获取文件md5校验的方法以及效率对比,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • Go语言map不支持并发写操作的原因

    Go语言map不支持并发写操作的原因

    Go语言为什么不支持并发读写map​,Go官方的说法是在多数情况下map只存在并发读操作,如果原生支持并发读写,即降低了并发读操作的性能,在使用 map 时,要特别注意是否存在对 map 的并发写操作,如果存在,要结合 sync 包的互斥锁一起使用,
    2024-01-01

最新评论