14 KiB
14 KiB
HTTP Restful工具文档
概述
HTTP Restful工具提供了标准化的HTTP请求和响应处理功能,采用Handler黑盒模式,封装了ResponseWriter和Request,提供简洁的API,无需每次都传递这两个参数。
功能特性
- 黑盒模式:封装
ResponseWriter和Request,提供简洁的API - 标准化的响应结构:
{code, message, timestamp, data} - 分离HTTP状态码和业务状态码
- 支持分页响应
- 提供便捷的请求参数解析方法
- 支持JSON请求体解析
响应结构
标准响应结构
{
"code": 0,
"message": "success",
"timestamp": 1704067200,
"data": {}
}
分页响应结构
{
"code": 0,
"message": "success",
"timestamp": 1704067200,
"data": {
"list": [],
"total": 100,
"page": 1,
"pageSize": 10
}
}
使用方法
1. 创建Handler
import (
"net/http"
commonhttp "git.toowon.com/jimmy/go-common/http"
)
// 方式1:使用HandleFunc包装器(推荐,最简洁)
func GetUser(h *commonhttp.Handler) {
id := h.GetQueryInt64("id", 0)
h.Success(data)
}
http.HandleFunc("/user", commonhttp.HandleFunc(GetUser))
// 方式2:手动创建Handler(需要更多控制时)
http.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
h := commonhttp.NewHandler(w, r)
GetUser(h)
})
2. 成功响应
func handler(h *commonhttp.Handler) {
// 简单成功响应(data为nil)
h.Success(nil)
// 带数据的成功响应
data := map[string]interface{}{
"id": 1,
"name": "test",
}
h.Success(data)
// 带消息的成功响应
h.SuccessWithMessage("操作成功", data)
}
3. 错误响应
func handler(h *commonhttp.Handler) {
// 业务错误(HTTP 200,业务code非0)
h.Error(1001, "用户不存在")
// 系统错误(HTTP 500)
h.SystemError("服务器内部错误")
// 其他HTTP错误状态码,使用WriteJSON直接指定
// 请求错误(HTTP 400)
h.WriteJSON(http.StatusBadRequest, 400, "请求参数错误", nil)
// 未授权(HTTP 401)
h.WriteJSON(http.StatusUnauthorized, 401, "未登录", nil)
// 禁止访问(HTTP 403)
h.WriteJSON(http.StatusForbidden, 403, "无权限访问", nil)
// 未找到(HTTP 404)
h.WriteJSON(http.StatusNotFound, 404, "资源不存在", nil)
}
4. 分页响应
func handler(h *commonhttp.Handler) {
// 获取分页参数
pagination := h.ParsePaginationRequest()
page := pagination.GetPage()
pageSize := pagination.GetSize()
// 查询数据(示例)
list, total := getDataList(page, pageSize)
// 返回分页响应(使用默认消息)
h.SuccessPage(list, total, page, pageSize)
// 返回分页响应(自定义消息)
h.SuccessPage(list, total, page, pageSize, "查询成功")
}
5. 解析请求
解析JSON请求体
func handler(h *commonhttp.Handler) {
type CreateUserRequest struct {
Name string `json:"name"`
Email string `json:"email"`
}
var req CreateUserRequest
if err := h.ParseJSON(&req); err != nil {
h.WriteJSON(http.StatusBadRequest, 400, "请求参数解析失败", nil)
return
}
// 使用req...
}
获取查询参数
func handler(h *commonhttp.Handler) {
// 获取字符串参数
name := h.GetQuery("name", "")
email := h.GetQuery("email", "default@example.com")
// 获取整数参数
id := h.GetQueryInt("id", 0)
age := h.GetQueryInt("age", 18)
// 获取int64参数
userId := h.GetQueryInt64("userId", 0)
// 获取布尔参数
isActive := h.GetQueryBool("isActive", false)
// 获取浮点数参数
price := h.GetQueryFloat64("price", 0.0)
}
获取表单参数
func handler(h *commonhttp.Handler) {
// 获取表单字符串
name := h.GetFormValue("name", "")
// 获取表单整数
age := h.GetFormInt("age", 0)
// 获取表单int64
userId := h.GetFormInt64("userId", 0)
// 获取表单布尔值
isActive := h.GetFormBool("isActive", false)
}
获取请求头
func handler(h *commonhttp.Handler) {
token := h.GetHeader("Authorization", "")
contentType := h.GetHeader("Content-Type", "application/json")
}
获取分页参数
方式1:使用 PaginationRequest 结构(推荐)
func handler(h *commonhttp.Handler) {
// 定义请求结构(包含分页字段)
type ListUserRequest struct {
Keyword string `json:"keyword"`
commonhttp.PaginationRequest // 嵌入分页请求结构
}
// 从JSON请求体解析(分页字段会自动解析)
var req ListUserRequest
if err := h.ParseJSON(&req); err != nil {
h.WriteJSON(http.StatusBadRequest, 400, "请求参数解析失败", nil)
return
}
// 使用分页方法
page := req.GetPage() // 获取页码(默认1)
size := req.GetSize() // 获取每页数量(默认20,最大100,优先使用page_size)
offset := req.GetOffset() // 计算偏移量
}
// 或者从查询参数/form解析分页
func handler(h *commonhttp.Handler) {
pagination := h.ParsePaginationRequest()
page := pagination.GetPage()
size := pagination.GetSize()
offset := pagination.GetOffset()
}
获取时区
func handler(h *commonhttp.Handler) {
// 从请求的context中获取时区
// 如果使用了middleware.Timezone中间件,可以从context中获取时区信息
// 如果未设置,返回默认时区 AsiaShanghai
timezone := h.GetTimezone()
}
6. 访问原始对象
如果需要访问原始的ResponseWriter或Request:
func handler(h *commonhttp.Handler) {
// 获取原始ResponseWriter
w := h.ResponseWriter()
// 获取原始Request
r := h.Request()
// 获取Context
ctx := h.Context()
}
完整示例
package main
import (
"log"
"net/http"
commonhttp "git.toowon.com/jimmy/go-common/http"
)
// 用户结构
type User struct {
ID int64 `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
// 用户列表接口
func GetUserList(h *commonhttp.Handler) {
// 获取分页参数
pagination := h.ParsePaginationRequest()
page := pagination.GetPage()
pageSize := pagination.GetSize()
// 获取查询参数
keyword := h.GetQuery("keyword", "")
// 查询数据
users, total := queryUsers(keyword, page, pageSize)
// 返回分页响应
h.SuccessPage(users, total, page, pageSize)
}
// 创建用户接口
func CreateUser(h *commonhttp.Handler) {
// 解析请求体
var req struct {
Name string `json:"name"`
Email string `json:"email"`
}
if err := h.ParseJSON(&req); err != nil {
h.WriteJSON(http.StatusBadRequest, 400, "请求参数解析失败", nil)
return
}
// 参数验证
if req.Name == "" {
h.Error(1001, "用户名不能为空")
return
}
// 创建用户
user, err := createUser(req.Name, req.Email)
if err != nil {
h.SystemError("创建用户失败")
return
}
// 返回成功响应
h.SuccessWithMessage("创建成功", user)
}
// 获取用户详情接口
func GetUser(h *commonhttp.Handler) {
// 获取查询参数
id := h.GetQueryInt64("id", 0)
if id == 0 {
h.WriteJSON(http.StatusBadRequest, 400, "用户ID不能为空", nil)
return
}
// 查询用户
user, err := getUserByID(id)
if err != nil {
h.SystemError("查询用户失败")
return
}
if user == nil {
h.Error(1002, "用户不存在")
return
}
h.Success(user)
}
func main() {
// 使用HandleFunc包装器(推荐)
http.HandleFunc("/users", commonhttp.HandleFunc(func(h *commonhttp.Handler) {
switch h.Request().Method {
case http.MethodGet:
GetUserList(h)
case http.MethodPost:
CreateUser(h)
default:
h.WriteJSON(http.StatusMethodNotAllowed, 405, "方法不支持", nil)
}
}))
http.HandleFunc("/user", commonhttp.HandleFunc(GetUser))
log.Println("Server started on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
API 参考
Handler结构
Handler封装了ResponseWriter和Request,提供更简洁的API。
type Handler struct {
w http.ResponseWriter
r *http.Request
}
创建Handler
NewHandler(w http.ResponseWriter, r *http.Request) *Handler
创建Handler实例。
HandleFunc(fn func(*Handler)) http.HandlerFunc
将Handler函数转换为标准的http.HandlerFunc(便捷包装器)。
示例:
http.HandleFunc("/users", commonhttp.HandleFunc(func(h *commonhttp.Handler) {
h.Success(data)
}))
Handler响应方法
(h *Handler) Success(data interface{})
成功响应,HTTP 200,业务code 0。
(h *Handler) SuccessWithMessage(message string, data interface{})
带消息的成功响应。
(h *Handler) Error(code int, message string)
业务错误响应,HTTP 200,业务code非0。
(h *Handler) SystemError(message string)
系统错误响应,HTTP 500,业务code 500。
(h *Handler) WriteJSON(httpCode, code int, message string, data interface{})
写入JSON响应(自定义)。
参数:
httpCode: HTTP状态码code: 业务状态码message: 响应消息data: 响应数据
(h *Handler) SuccessPage(list interface{}, total int64, page, pageSize int, message ...string)
分页成功响应。
参数:
list: 数据列表total: 总记录数page: 当前页码pageSize: 每页大小message: 响应消息(可选,如果为空则使用默认消息 "success")
Handler请求解析方法
(h *Handler) ParseJSON(v interface{}) error
解析JSON请求体。
(h *Handler) GetQuery(key, defaultValue string) string
获取查询参数(字符串)。
(h *Handler) GetQueryInt(key string, defaultValue int) int
获取查询参数(整数)。
(h *Handler) GetQueryInt64(key string, defaultValue int64) int64
获取查询参数(int64)。
(h *Handler) GetQueryBool(key string, defaultValue bool) bool
获取查询参数(布尔值)。
(h *Handler) GetQueryFloat64(key string, defaultValue float64) float64
获取查询参数(浮点数)。
(h *Handler) GetFormValue(key, defaultValue string) string
获取表单值(字符串)。
(h *Handler) GetFormInt(key string, defaultValue int) int
获取表单值(整数)。
(h *Handler) GetFormInt64(key string, defaultValue int64) int64
获取表单值(int64)。
(h *Handler) GetFormBool(key string, defaultValue bool) bool
获取表单值(布尔值)。
(h *Handler) GetHeader(key, defaultValue string) string
获取请求头。
(h *Handler) ParsePaginationRequest() *PaginationRequest
从请求中解析分页参数。
说明:
- 支持从查询参数和form表单中解析
- 优先级:查询参数 > form表单
- 如果请求体是JSON格式且包含分页字段,建议先使用
ParseJSON解析完整请求体到包含PaginationRequest的结构体中
(h *Handler) GetTimezone() string
从请求的context中获取时区。
说明:
- 如果使用了middleware.Timezone中间件,可以从context中获取时区信息
- 如果未设置,返回默认时区 AsiaShanghai
Handler访问原始对象
(h *Handler) ResponseWriter() http.ResponseWriter
获取原始的ResponseWriter(需要时使用)。
(h *Handler) Request() *http.Request
获取原始的Request(需要时使用)。
(h *Handler) Context() context.Context
获取请求的Context。
分页请求结构
PaginationRequest
分页请求结构,支持从JSON和form中解析分页参数。
字段:
Page: 页码(默认1)Size: 每页数量(兼容旧版本)PageSize: 每页数量(推荐使用,优先于Size)
方法:
GetPage() int: 获取页码,如果未设置则返回默认值1GetSize() int: 获取每页数量,优先使用PageSize,如果未设置则使用Size,默认20,最大100GetOffset() int: 计算数据库查询的偏移量
ParsePaginationRequest(r *http.Request) *PaginationRequest
从请求中解析分页参数(内部函数,Handler内部使用)。
状态码说明
HTTP状态码
200: 正常响应(包括业务错误)400: 请求参数错误401: 未授权403: 禁止访问404: 资源不存在500: 系统内部错误
业务状态码
0: 成功非0: 业务错误(具体错误码由业务定义)
注意事项
-
HTTP状态码与业务状态码分离:
- 业务错误(如用户不存在、参数验证失败等)返回HTTP 200,业务code非0
- 只有系统异常(如数据库连接失败、程序panic等)才返回HTTP 500
-
分页参数限制:
- page最小值为1
- pageSize最小值为1,最大值为100
-
响应格式统一:
- 所有响应都遵循标准结构
- timestamp为Unix时间戳(秒)
-
错误处理:
- 使用
Error方法返回业务错误(HTTP 200,业务code非0) - 使用
SystemError返回系统错误(HTTP 500) - 其他HTTP错误状态码(400, 401, 403, 404等)使用
WriteJSON方法直接指定
- 使用
-
黑盒模式:
- 所有功能都通过Handler对象调用,无需传递
w和r参数 - 代码更简洁,减少调用方工作量
- 所有功能都通过Handler对象调用,无需传递
示例
完整示例请参考 examples/http_handler_example.go