引入

Web 服务是当今应用的核心,Go 标准库自带的 net/http 包就能搭建 HTTP 服务器和客户端,不需要第三方框架。理解 net/http 包,就能用 Go 快速写出 REST API、爬虫、反向代理等网络应用。

正文

定义

定义

net/http 包提供 HTTP 服务器和客户端 功能。服务器端负责监听端口、接收请求、返回响应;客户端负责发起 HTTP 请求。内置路由匹配和中间件支持,是 Go Web 开发的基础。

语法

import "net/http"
 
// 启动服务器
http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello"))
})
http.ListenAndServe(":8080", nil)
 
// 发起客户端请求
resp, err := http.Get("http://localhost:8080/hello")

例子

最简单的 HTTP 服务器

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

HandleFunc 注册路由,ListenAndServe 启动服务器。访问 http://localhost:8080/hello 就能看到 hello world

处理请求参数

func handler(w http.ResponseWriter, r *http.Request) {
    name := r.URL.Query().Get("name")
    method := r.Method
    body, _ := io.ReadAll(r.Body)
    defer r.Body.Close()
 
    fmt.Fprintf(w, "method=%s, name=%s, body=%s", method, name, string(body))
}

r.Method 获取请求方法,r.URL.Query() 解析 URL 参数,r.Body 读取请求体。

返回 JSON 响应

func apiHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusOK)
    w.Write([]byte(`{"code": 0, "msg": "ok"}`))
}

w.Header().Set() 设置响应头,w.WriteHeader() 设置状态码,w.Write() 写入响应体。

HTTP 客户端

// GET 请求
resp, err := http.Get("https://example.com")
if err != nil {
    log.Fatal(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))
 
// POST 请求
resp, err := http.Post("https://example.com/api", "application/json",
    strings.NewReader(`{"key":"value"}`))
defer resp.Body.Close()

http.Gethttp.Post 是最简写法。resp.Bodyio.Reader,用完要 Close()

自定义客户端

client := &http.Client{
    Timeout: 10 * time.Second,
}
 
req, _ := http.NewRequest("PUT", "https://example.com/api/1",
    strings.NewReader(`{"name":"tom"}`))
req.Header.Set("Authorization", "Bearer token123")
 
resp, err := client.Do(req)
defer resp.Body.Close()

http.NewRequest 可以设置任意方法和请求头,client.Do 发送请求。需要设超时就用自定义客户端,默认客户端没有超时。

中间件

func logging(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        next.ServeHTTP(w, r)
        fmt.Printf("%s %s %v\n", r.Method, r.URL.Path, time.Since(start))
    })
}
 
mux := http.NewServeMux()
mux.HandleFunc("/api", apiHandler)
http.ListenAndServe(":8080", logging(mux))

中间件就是一个函数,包装原始 Handler 添加额外逻辑。Go 1.22+ 的 ServeMux 支持方法路由如 GET /api/users/{id}

常见写法

写法说明
http.ListenAndServe(addr, handler)启动 HTTP 服务器
http.HandleFunc(pattern, handler)注册路由处理函数
http.NewServeMux()创建自定义路由多路复用器
http.Get(url)发起 GET 请求
http.Post(url, contentType, body)发起 POST 请求
http.NewRequest(method, url, body)创建自定义请求
client.Do(req)用自定义客户端发送请求
r.URL.Query().Get(key)获取 URL 查询参数
r.Method获取请求方法
w.Header().Set(k, v)设置响应头
w.WriteHeader(code)设置响应状态码
http.FileServer(http.Dir("./static"))静态文件服务器

特点

  • net/http 内置 HTTP 服务器,不需要 Apache 或 Nginx 就能独立运行
  • HandlerFunc 让普通函数满足 Handler 接口,注册路由很方便
  • 客户端的 resp.Body 必须 Close(),否则连接泄漏
  • 默认客户端没有超时设置,生产环境务必自定义 Client
  • Go 1.22+ 的 ServeMux 支持方法和路径参数,不再需要第三方路由库
  • 中间件通过函数嵌套实现,简洁且灵活

理解

net/http 的设计很 Go 风格——接口驱动,组合优先。服务器端核心就是 Handler 接口,任何实现了 ServeHTTP 方法的类型都能处理请求。客户端用起来也简单,Get / Post 一行搞定,复杂场景用 NewRequest + client.Do。中间件就是套娃式的函数包装,理解了这个模式,整个 Go Web 生态(gin、echo)都是这套路。

引出

HTTP 请求和响应经常要传 JSON 数据,手动拼字符串太麻烦。接下来看 json 包,学习怎么在 Go 结构体和 JSON 之间自动转换。