直接用 net/http 是为了掌握请求处理、模板渲染和数据流转的全过程,确保每个环节可控且透明,便于调试博客系统。
net/http 而不用框架?因为你要的不是“快速上线”,而是理解请求怎么进、模板怎么出、数据怎么串。框架会帮你藏掉 http.ServeMux 的注册逻辑、隐藏 html/template 的执行上下文、甚至自动处理 Conten。一旦路由错位或模板变量未定义,你连错误在哪都看不到。
用原生方式,每个环节可控:HTTP 处理函数明确接收 *http.Request 和 http.ResponseWriter;模板渲染必须显式调用 tmpl.Execute();所有错误都要手动检查——这反而是调试博客系统最需要的透明度。
http.HandleFunc 怎么组织博客路由?别写成一长串 if r.URL.Path == "/post/1" 判断。用前缀分组 + 路径提取更可靠:
/ → 首页,列出文章摘要/post/ → 单篇文章页,用 strings.TrimPrefix(r.URL.Path, "/post/") 提取 ID/static/ → 静态资源,必须加前缀拦截,否则模板里引用的 CSS/JS 会 404关键点:静态文件不能靠 http.FileServer 直接挂根路径,否则会覆盖你自己的路由。正确做法是用 http.StripPrefix 剥离前缀再交给 FileServer:
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("./static"))))
html/template 渲染时变量和函数怎么传?模板不是字符串拼接,它有作用域和安全机制。你不能在模板里直接调用 time.Now() 或 len(),除非显式注册函数:
Post.Title 可以访问,post.title 不行funcMap := template.FuncMap{"formatTime": func(t time.Time) string { return t.Format("2006-01-02") }}
{{ .CreatedAt | formatTime }},注意管道符 | 是必须的nil 数据却没做判断,tmpl.Execute() 会 panic,务必加 {{ if .Posts }}...{{ end }}
常见错误:把整个 map[string]interface{} 当作根对象传进去,结果模板里写 {{ .Title }} 找不到——其实该写 {{ .Data.Title }} 或提前解构。
博客页面通常有公共头尾,用 {{ define "header" }} 和 {{ template "header" . }} 是标准解法,但要注意两点:
index.html、post.html)必须用同一个 template.ParseGlob("templates/*.html") 加载,否则 template "header" 找不到定义./static/css/main.css,浏览器请求的是相对 HTML 页面的路径,应统一用 /static/css/main.css
http.FileServer 正确识别,返回 text/plain,浏览器直接拒解析——确保 ./static 下文件扩展名合法(如 .css、.js)真正卡住人的往往不是语法,而是 HTTP 响应头没设对、模板文件没加载全、或者路径多了一个斜杠导致 404 后还继续执行了 Execute 报 panic。