GET 把参数拼在 URL 上,POST 把参数揣在请求体(send)里发出去。
POST 三要素:
1. open——第一个参数写 'post'
2. setRequestHeader——必写表单请求头
3. send——参数字符串放这里
坑:POST 参数不能拼 URL、忘了 setRequestHeader 后端认不出格式、open 第三个参数默认 true 异步别写成 false。
最大的区别就是参数放哪。GET 把参数拼在 URL 后面(?page=1&size=10),POST 把参数放在请求体里(send 里),URL 干干净净。
// GET:参数拼在 URL 上,一眼能看见
xhr.open('GET', '/list?page=1&size=10', true);
// GET 没有请求体,send 给 null
xhr.send(null);
// POST:参数不拼 URL,放 send 里
xhr.open('POST', '/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// 参数揣兜里
xhr.send('username=zhangsan&password=123456');
登录、提交表单、上传数据这类"往服务器写东西"的用 POST;查询、拿列表这类"只读"的用 GET。POST 参数不在 URL 里,相对安全一些(但也不是加密,敏感数据该 https 还是要 https)。
POST 的请求体可以是各种格式:表单格式、JSON 格式、文件二进制……后端不知道你发的是哪种,所以你得用请求头告诉它"我发的是表单格式"。这一行少写,后端就按默认方式解析,经常把你的参数读成乱码。
// 表单格式(最常见,和原生 form 提交一样)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// 参数长这样:username=zhangsan&password=123456
// JSON 格式(现在前后端分离更常用)
xhr.setRequestHeader('Content-Type', 'application/json');
// 参数长这样:'{"username":"zhangsan","password":"123456"}'
发什么格式,就声明什么 Content-Type,两边必须对上。前端发表单格式,后端按表单解析;前端发 JSON,后端按 JSON 解析。对不上就"参数收不到"。
xhr.open(method, url, async) 第三个参数就是"是否异步"。默认 true(异步)——请求发出去后浏览器继续干别的事,数据回来了再触发 onreadystatechange。写成 false 就是同步——浏览器会卡在那一行等服务器返回,期间页面整个卡死点不动。
// 异步(默认,永远这么写):
// true = 异步,不卡页面
xhr.open('POST', '/login', true);
// 回来再回调
xhr.onreadystatechange = function () { ... };
xhr.send(params);
// 同步(几乎不要这么写):
// false = 同步,页面卡死
xhr.open('POST', '/login', false);
// 卡到服务器返回才往下走
xhr.send(params);
// 这里直接能拿到
let data = xhr.responseText;
永远用异步(true 或不传)。同步会冻结整个页面,用户以为浏览器崩了。现在没人用同步 XHR,fetch / axios 默认也都是异步。
可能在什么地方用:登录注册、提交表单、发表评论、上传数据、改个人资料——凡是"往服务器写"的接口都是 POST。
常见的问题:
1. POST 参数拼到 URL 上去了(应该放 send)
2. 忘了 setRequestHeader,后端收不到参数
3. Content-Type 和参数格式对不上(发了 JSON 却声明表单)
4. 把 open 第三个参数写成 false,页面卡死。
解决思路:参数收不到就去 Network 看 Payload 里到底发出去了什么;格式问题就核对 Content-Type 和参数串长得对不对;页面卡死就是同步了,改回 true。
练习:POST 登录
1. 用原生 XHR 写一个 POST 登录请求,参数 username / password 放 send
2. 加上 setRequestHeader,声明表单格式
3. 在 onreadystatechange 里判断 readyState===4 && status===200,再 JSON.parse
4. 把 Content-Type 改成 application/json 再试一次,观察参数格式变化。
| API | 作用 | 参数怎么传 | 返回/结果 | 代码示例 |
|---|---|---|---|---|
| xhr.open("post",url) | 用 POST 方式发请求 | 入参:"post"、地址 | 返回:无 | xhr.open("post", "/login", true); |
| xhr.setRequestHeader(k,v) | 告诉后端参数是什么格式 | 入参:"Content-Type"、表单格式 | 返回:无 | xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); |
| xhr.send(body) | 把参数揣兜里发出去 | 入参:参数字符串 | 返回:无 | xhr.send("account=zs&pwd=123"); |
| xhr.status===200 | 判断这次请求成功没 | 无 | 返回:true / false | if (xhr.status === 200) { } |