GET请求无请求体,参数全在URL中,如“GET /login?username=admin&password=123456 HTTP/1.1”,Content-Length为0,Content-Type不存在;服务器只解析query string,故需读req.query而非req.body。

GET请求的HTTP报文长什么样
浏览器发起 method="get" 表单提交时,根本不会发请求体(Request Body),所有字段都拼进 URL,最终生成的是一条类似这样的完整请求行:
GET /login?username=admin&password=123456 HTTP/1.1
后面跟着 Host、User-Agent 等标准头,但 Content-Length 为 0,Content-Type 不存在。服务器收到后,只解析 URL 中的 query string,所以 Express 里必须读 req.query,读 req.body 必然为空。
- URL 长度超限(比如含大量复选框或长文本)会导致参数被截断,且不同浏览器/服务器阈值不一(Chrome 约 2MB,但实际建议控制在 2KB 内)
- 空格变成
+,中文变成%E4%BD%A0,但如果原始 value 里有未编码的&或=,会直接破坏参数结构 -
enctype属性在 GET 表单中完全被忽略,设成multipart/form-data也没用,<input type="file">字段压根不会被序列化
POST请求的HTTP报文关键字段
method="post" 提交时,URL 干净,数据全在 body 里,报文典型结构是:
POST /login HTTP/1.1 Content-Type: application/x-www-form-urlencoded Content-Length: 32 username=admin&password=123456
注意两点:一是 Content-Type 头必须匹配实际编码方式;二是后端必须启用对应中间件(如 Express 的 express.urlencoded())才能把 body 解析成 req.body 对象。漏配中间件,req.body 就是 {}。
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 如果上传文件,
Content-Type必须是multipart/form-data,且表单要显式写enctype="multipart/form-data",否则后端只能收到文件名字符串,拿不到二进制流 - 用
application/json?原生<form>不支持该 enctype,那是 AJAX 场景的事 - POST 默认不缓存,但若后端响应头写了
Cache-Control: max-age=3600,仍可能被缓存——这在重复提交场景下很危险
为什么 req.body 是空对象?常见配置错位点
80% 的 “收不到参数” 问题,不是代码写错,而是前后端约定断裂。核心就三条:
- 表单
method写成"GET"(大写)或"post"(小写混用),浏览器会降级为默认get,但后端却在等req.body - 漏写
method属性 → 浏览器按规范默认用get→ 后端从req.body读,必然空 - Express 项目没加
express.urlencoded({ extended: true }),或没放在路由前,req.body就永远是空对象
PHP 或 Flask 也一样:Flask 里 request.args 对应 GET,request.form 对应 POST;PHP 的 $_GET 和 $_POST 严格分离,混用就丢数据。
选型不能只看“传多传少”,得看语义和副作用
别再记“GET 传短、POST 传长”。真正决定选哪个的,是操作意图:
- 搜索、分页、查看详情 → 用 GET:幂等、可 bookmark、可刷新重试,URL 本身就有意义
- 登录、下单、发评论、改密码 → 用 POST:非幂等,必须防重复(靠后端幂等 key 或 PRG 模式跳转),且敏感字段不能暴露在 URL 或历史记录里
- 带文件的表单 → 只能用 POST +
enctype="multipart/form-data",二者缺一不可
最易被忽略的是刷新行为:用户 F5 刷新一个 POST 成功页,浏览器大概率弹“确认重新提交”——这不是保护机制,点了“确定”就真会再扣一次款。真正的防线在后端,不在前端禁用按钮。


















