直接刷新页面会重复提交表单,因浏览器重发上一个post请求;须用prg模式(redirect()中断post)和一次性form token(服务端session生成校验)双重防护,csrf token与此无关。

为什么直接刷新页面会重复提交表单
用户点击“提交”后,浏览器发出 POST 请求;如果服务端处理完没跳转,用户按 F5 或点后退再前进,浏览器会重发上一个 POST —— Django 不会自动拦截,request.POST 依然有效,视图照常执行。这不是前端防抖能解决的,得在服务端切断重复路径。
用 redirect() + HttpResponseRedirect 中断 POST 生命周期
核心是遵守 PRG 模式(Post-Redirect-Get):接收 POST 后立刻重定向到一个 GET 页面,让浏览器地址栏变成新 URL。这样刷新时只重复 GET,不会再次触发表单逻辑。
- 视图处理成功后必须返回
redirect("success_page")或HttpResponseRedirect,不能直接render()成功页 - 重定向目标页(如
"post_success")应是独立视图,只负责展示结果,不处理任何表单数据 - 若需传递提示信息,用
messages.success(request, "提交成功"),它依赖 session 自动跨重定向存活
Session 令牌(Token)怎么生成和校验
Token 是更主动的防护:每次渲染表单时塞一个一次性随机字符串进 hidden 字段和 session,提交时比对两者,匹配则消费掉 token(del request.session["form_token"]),下次提交就失效。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
- 生成:在 GET 视图里用
secrets.token_urlsafe(16)生成,存入request.session["form_token"],再传给模板:<input type="hidden" name="token" value="{{ token }}"> - 校验:POST 视图中先检查
request.POST.get("token") == request.session.get("form_token"),再del request.session["form_token"] - 注意:不要用
request.COOKIES或前端 localStorage 存 token,session 是服务端可控的唯一可信位置
CSRF Token 和 Form Token 是两回事
Django 默认的 {% csrf_token %} 防的是跨站请求伪造,不是重复提交。它随每个页面生成、长期有效(只要 session 活着),而防重复的 form token 必须“一次一换”。两者要共存:表单里既有 {% csrf_token %},也要手动加自己的 token hidden 字段。
- CSRF Token 失效会导致 403 错误,提示 “Forbidden (403) CSRF verification failed.”
- Form Token 校验失败应返回 400 或重定向回原表单页,并提示“操作已生效,请勿重复提交”
- 如果用了 Class-Based View(如
CreateView),要在form_valid()里手动删 session token,不能只靠super().form_valid()
真正难的是 token 生命周期管理:生成时机、存储位置、消费判断、失败降级策略——这些细节错一点,防重就形同虚设。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










