
本文详解如何使用 Go 构建轻量级日志服务,正确解析 JSON 格式的 POST 请求体,并安全、高效地持久化到本地文件,同时避免常见误区(如误用 ParseForm 处理非表单数据)。
本文详解如何使用 go 构建轻量级日志服务,正确解析 json 格式的 post 请求体,并安全、高效地持久化到本地文件,同时避免常见误区(如误用 `parseform` 处理非表单数据)。
在 Go 中构建日志接收服务时,一个常见误区是直接调用 r.ParseForm() 来处理任意 POST 请求——该方法仅适用于 application/x-www-form-urlencoded 或 multipart/form-data 类型的表单数据,而对 application/json 等原始请求体无效。这正是原代码输出 map[] 的根本原因:r.Form 为空,r.FormValue("hello") 自然无法提取 JSON 字段。
要正确接收并保存 JSON(或其他任意格式)的 POST 数据,应直接读取 r.Body。以下是完整、健壮的实现方案:
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
)
func logger(w http.ResponseWriter, r *http.Request) {
// 1. 验证请求方法
if r.Method != http.MethodPost {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
// 2. 读取原始请求体(注意:Body 只能读取一次)
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Failed to read request body", http.StatusBadRequest)
log.Printf("Error reading body: %v", err)
return
}
defer r.Body.Close() // 确保资源释放
// 3. 写入文件(推荐使用 os.OpenFile + Write,便于追加/权限控制)
f, err := os.OpenFile("logs.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
http.Error(w, "Failed to open log file", http.StatusInternalServerError)
log.Printf("Error opening file: %v", err)
return
}
defer f.Close()
// 4. 写入带时间戳的日志行(增强可读性与调试性)
timestamp := fmt.Sprintf("[%s] ", r.RemoteAddr)
if _, writeErr := f.WriteString(timestamp + string(body) + "\n"); writeErr != nil {
http.Error(w, "Failed to write to log file", http.StatusInternalServerError)
log.Printf("Error writing to file: %v", writeErr)
return
}
// 5. 返回成功响应
w.WriteHeader(http.StatusOK)
w.Write([]byte("Log received and saved"))
}
func main() {
http.HandleFunc("/log", logger)
fmt.Println("Logging server started on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}关键注意事项:
- ✅ 不要滥用 ParseForm():它不解析 JSON 或纯文本请求体;仅用于表单编码数据。
- ✅ 务必 defer r.Body.Close():防止连接泄漏,尤其在高并发场景下至关重要。
- ✅ 使用 os.OpenFile 而非 ioutil.WriteFile(已弃用):WriteFile 每次覆盖整个文件,不适合日志;OpenFile 支持追加模式(O_APPEND),更符合日志服务语义。
- ✅ 添加 HTTP 状态码校验与错误响应:提升服务健壮性与可观测性。
- ✅ 考虑生产环境增强项:如日志轮转(lumberjack)、结构化日志(zerolog/zap)、限流、HTTPS 支持及请求体大小限制(http.MaxBytesReader)。
通过以上实现,你的 Go 日志服务即可高效、可靠地接收 curl -H "Content-Type: application/json" -X POST -d '{"hello":"world"}' http://localhost:8080/log 等请求,并将原始数据按行追加至 logs.txt,为后续分析提供坚实基础。










