
本文介绍如何为 Go 标准库 http.FileServer 添加 404 请求日志功能,通过包装 http.ResponseWriter 和 http.Handler 捕获响应状态码,实现在控制台输出缺失文件的访问记录。
本文介绍如何为 go 标准库 `http.fileserver` 添加 404 请求日志功能,通过包装 `http.responsewriter` 和 `http.handler` 捕获响应状态码,实现在控制台输出缺失文件的访问记录。
Go 的 http.FileServer 默认不会打印任何日志,即使返回了 404 Not Found,也不会在服务端控制台显示。这是因为 http.FileServer 和 http.StripPrefix 返回的 http.Handler 实现仅负责处理请求与响应,不包含日志逻辑。要实现 404 日志,需手动拦截响应过程,获取实际写入的状态码并据此记录。
由于标准 http.ResponseWriter 接口不提供读取已设置状态码的方法(WriteHeader 是单向调用),我们需要创建一个包装器(wrapper),在 WriteHeader 被调用时缓存状态码,供后续检查使用。
以下是完整的可运行实现:
package main
import (
"log"
"net/http"
"path"
)
// StatusRespWr 包装 http.ResponseWriter,用于捕获写入的状态码
type StatusRespWr struct {
http.ResponseWriter
status int
}
func (w *StatusRespWr) WriteHeader(status int) {
w.status = status
w.ResponseWriter.WriteHeader(status)
}
// wrapHandler 将任意 Handler 包装为带错误日志能力的 HandlerFunc
func wrapHandler(h http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
srw := &StatusRespWr{
ResponseWriter: w,
status: 200, // 默认成功状态,避免未调用 WriteHeader 时为 0
}
h.ServeHTTP(srw, r)
if srw.status >= 400 {
log.Printf("4xx/5xx error: %d for path %q from %s",
srw.status, r.RequestURI, r.RemoteAddr)
}
}
}
func main() {
dirPath := "/test" // 替换为你的实际静态资源目录
fileServer := http.FileServer(http.Dir(dirPath))
// 注意:StripPrefix 的前缀应为路径前缀(如 "/o"),而非拼接后的 "/o/<dirPath>"
// 正确做法是先 StripPrefix("/o"),再交由 FileServer 处理相对路径
handler := http.StripPrefix("/o", fileServer)
http.HandleFunc("/o/", wrapHandler(handler))
log.Println("Serving files at :8181, prefix /o/")
log.Fatal(http.ListenAndServe(":8181", nil))
}? 关键注意事项:
- http.StripPrefix 的第一个参数必须是请求路径的前缀字符串(如 "/o"),而非 path.Join("/o", dirPath) —— 后者会导致路径匹配失败或行为异常;
- StatusRespWr.status 初始化为 200,防止因 FileServer 内部未显式调用 WriteHeader(例如直接 Write 触发隐式 200)导致 srw.status == 0 的误判;
- 日志中建议加入 r.RemoteAddr,便于追踪来源 IP;生产环境可进一步集成结构化日志(如 zap)或写入文件;
- 若需区分 404 与其他错误(如 403、500),可将条件改为 srw.status == http.StatusNotFound;
- 此方案适用于所有基于 http.Handler 的中间件扩展场景,具备良好的通用性和可复用性。
通过上述封装,你即可在终端实时看到类似以下日志:
2024/06/15 14:22:31 4xx/5xx error: 404 for path "/o/missing.jpg" from 127.0.0.1:54321
这不仅提升了调试效率,也为后续监控、审计或安全分析提供了基础数据支撑。


















