4. 基础HTTP服务搭建:使用net/http与Gin构建RESTful API
在微服务架构中,HTTP服务是限流与熔断策略的承载层。本章将分别使用Go标准库net/http和流行框架Gin搭建一个具备路由、中间件、JSON响应能力的RESTful API服务,为后续集成限流熔断组件奠定基础。
4.1 服务架构概览
一个基础HTTP服务通常包含以下层级:
- 路由层:定义URL路径与处理函数的映射关系。
- 中间件层:执行请求日志、鉴权、限流等横切关注点。
- 处理层:解析请求参数、调用业务逻辑、返回响应。
- 响应层:统一封装JSON格式的成功或错误信息。
架构要点:限流熔断组件通常以中间件形式插入路由与处理层之间,因此服务搭建时必须预留中间件扩展点。
4.2 使用net/http搭建基础服务
Go标准库net/http提供了完整的HTTP服务能力,无需第三方依赖即可构建RESTful API。以下是一个包含路由、中间件和JSON响应的完整示例。
4.2.1 项目结构
http-basic/
├── main.go
├── handler/
│ └── user.go
├── middleware/
│ └── logger.go
└── response/
└── json.go
4.2.2 核心代码实现
main.go:注册路由并启动服务。
package main
import (
"log"
"net/http"
"http-basic/handler"
"http-basic/middleware"
)
func main() {
mux := http.NewServeMux()
// 注册路由
mux.HandleFunc("/api/v1/users", handler.GetUsers)
mux.HandleFunc("/api/v1/users/", handler.GetUserByID)
// 包装中间件
wrappedMux := middleware.Logger(mux)
log.Println("HTTP服务启动于 :8080")
if err := http.ListenAndServe(":8080", wrappedMux); err != nil {
log.Fatalf("服务启动失败: %v", err)
}
}
middleware/logger.go:请求日志中间件。
package middleware
import (
"log"
"net/http"
"time"
)
func Logger(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("[%s] %s %s %v", r.Method, r.RequestURI, r.RemoteAddr, time.Since(start))
})
}
handler/user.go:用户处理函数。
package handler
import (
"net/http"
"strconv"
"strings"
"http-basic/response"
)
func GetUsers(w http.ResponseWriter, r *http.Request) {
users := []map[string]interface{}{
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"},
}
response.JSON(w, http.StatusOK, users)
}
func GetUserByID(w http.ResponseWriter, r *http.Request) {
idStr := strings.TrimPrefix(r.URL.Path, "/api/v1/users/")
id, err := strconv.Atoi(idStr)
if err != nil {
response.JSON(w, http.StatusBadRequest, map[string]string{"error": "invalid user id"})
return
}
response.JSON(w, http.StatusOK, map[string]interface{}{"id": id, "name": "User" + idStr})
}
response/json.go:统一JSON响应封装。
package response
import (
"encoding/json"
"net/http"
)
func JSON(w http.ResponseWriter, status int, data interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(data)
}
net/http 适用场景:适合对依赖管理要求严格、追求最小二进制体积、或需要深度定制HTTP层的项目。但路由能力较弱(不支持路径参数、方法匹配),需自行解析。
4.3 使用Gin框架搭建服务
Gin是目前Go生态中最流行的HTTP框架之一,提供高性能路由、中间件链、参数绑定、错误恢复等开箱即用的能力。以下使用Gin重构上述服务。
4.3.1 安装Gin
go get -u github.com/gin-gonic/gin
4.3.2 核心代码实现
main.go:使用Gin引擎注册路由与中间件。
package main
import (
"github.com/gin-gonic/gin"
"gin-basic/handler"
"gin-basic/middleware"
)
func main() {
r := gin.Default() // 默认包含Logger和Recovery中间件
// 自定义中间件
r.Use(middleware.CustomLogger())
// 路由组
v1 := r.Group("/api/v1")
{
v1.GET("/users", handler.GetUsers)
v1.GET("/users/:id", handler.GetUserByID)
}
r.Run(":8080") // 默认监听 :8080
}
middleware/logger.go:自定义日志中间件。
package middleware
import (
"log"
"time"
"github.com/gin-gonic/gin"
)
func CustomLogger() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
c.Next()
log.Printf("[GIN] %s %s %d %v",
c.Request.Method,
c.Request.URL.Path,
c.Writer.Status(),
time.Since(start))
}
}
handler/user.go:使用Gin的上下文处理请求。
package handler
import (
"net/http"
"github.com/gin-gonic/gin"
)
func GetUsers(c *gin.Context) {
users := []gin.H{
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"},
}
c.JSON(http.StatusOK, users)
}
func GetUserByID(c *gin.Context) {
id := c.Param("id")
c.JSON(http.StatusOK, gin.H{"id": id, "name": "User" + id})
}
4.4 net/http vs Gin 对比
| 特性 | net/http | Gin |
|---|---|---|
| 依赖 | 无第三方依赖 | 需引入Gin包 |
| 路由能力 | 仅支持固定路径和前缀匹配 | 支持路径参数、路由组、方法匹配 |
| 中间件 | 需手动包装Handler | 内置中间件链,Use/Group灵活组合 |
| 参数解析 | 手动解析r.URL.Query/r.Form | c.Query/c.Param/c.ShouldBindJSON |
| JSON响应 | 手动设置Header和Encoder | c.JSON自动设置Content-Type |
| 性能 | 原生高性能 | 接近原生,路由树优化 |
| 错误恢复 | 需自行实现Recovery | 内置Recovery中间件 |
| 社区生态 | 标准库,稳定 | 丰富插件与文档 |
选型建议:本课程后续的限流熔断集成将基于Gin框架,因为其中间件机制更贴合限流组件的插入模式。若你所在项目强制使用标准库,也可参考net/http版本自行封装中间件链。
4.5 中间件扩展点设计
无论使用哪种框架,中间件都是限流熔断的核心扩展点。以下是一个预留限流中间件占位的示例:
// Gin 版本:预留限流中间件
func RateLimitMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
// TODO: 第5章实现限流逻辑
// 如果限流触发,直接返回 429 Too Many Requests
// c.AbortWithStatusJSON(429, gin.H{"error": "rate limit exceeded"})
// return
c.Next()
}
}
// 注册时插入
r.Use(middleware.RateLimitMiddleware())
4.6 启动与验证
完成代码编写后,通过以下步骤验证服务是否正常运行:
- 启动服务:在项目根目录执行
go run main.go。 - 测试GET请求:
# 获取用户列表
curl http://localhost:8080/api/v1/users
# 获取单个用户
curl http://localhost:8080/api/v1/users/42
- 预期响应:
// GET /api/v1/users
[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]
// GET /api/v1/users/42
{"id":"42","name":"User42"}
关键检查点:确认中间件日志正常输出、JSON响应格式正确、路由路径参数解析无误。这些是后续集成限流熔断组件时的基础验证条件。
4.7 本章小结
- 使用
net/http搭建了无依赖的基础HTTP服务,理解标准库的路由与中间件机制。 - 使用
Gin框架搭建了具备路由组、中间件链、参数绑定的RESTful API服务。 - 通过对比表格明确了两种方案的适用场景与差异。
- 在中间件链中预留了限流与熔断的插入点,为后续章节的组件集成做好准备。