1. HTTP请求基础:GET与POST的本质区别
在Web开发中,GET和POST是HTTP协议最常用的两种请求方法。虽然表面上看都是向服务器发送数据,但底层机制和适用场景有本质区别。
GET请求的特点就像在明信片上写字 - 所有信息都暴露在URL中。当你访问https://example.com/search?q=keyword&page=2时,q=keyword和page=2这些参数直接附加在URL后面,用问号(?)分隔主地址和参数,用&符号连接多个参数。这种设计带来三个重要特性:
- 参数可见性:所有参数都显示在浏览器地址栏
- 长度限制:URL最长约2048个字符(不同浏览器有差异)
- 幂等性:多次执行相同GET请求不会改变服务器状态
POST请求则像寄挂号信 - 数据放在信封(请求体)里。当提交表单或上传文件时,数据不会出现在URL中,而是打包在HTTP请求的body部分。这带来完全不同的特性:
- 参数不可见:数据不会显示在地址栏
- 无长度限制:可发送大量数据(如图片、视频)
- 非幂等性:多次提交可能产生不同结果(如重复下单)
关键区别:GET适合获取数据,POST适合修改数据。这是RESTful API设计的基本原则。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 发送普通参数的具体实现
2.1 GET请求参数发送实战
GET请求发送参数有两种主流方式:
方式一:URL拼接(原生JavaScript)
javascript复制const params = new URLSearchParams({
username: 'john_doe',
page: 1,
limit: 20
});
fetch(`https://api.example.com/users?${params}`)
.then(response => response.json())
.then(data => console.log(data));
方式二:axios库(更简洁)
javascript复制axios.get('https://api.example.com/users', {
params: {
username: 'john_doe',
page: 1,
limit: 20
}
})
.then(response => console.log(response.data));
注意事项:
- 参数值需要encodeURIComponent()编码处理特殊字符
- 敏感信息(如密码)绝对不要用GET发送
- 复杂数据结构(嵌套对象)不适合GET请求
2.2 POST请求参数发送方案
POST请求发送普通表单数据常见三种编码格式:
application/x-www-form-urlencoded(默认表单格式)
javascript复制const data = new URLSearchParams();
data.append('username', 'john_doe');
data.append('password', 's3cret');
fetch('https://api.example.com/login', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: data
});
multipart/form-data(文件上传)
javascript复制const formData = new FormData();
formData.append('avatar', fileInput.files[0]);
formData.append('description', 'Profile photo');
axios.post('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
application/json(现代API常用)
javascript复制fetch('https://api.example.com/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'John',
age: 30,
hobbies: ['reading', 'hiking']
})
});
3. 参数处理的安全陷阱与防御
3.1 常见安全问题及解决方案
| 安全问题 | 风险表现 | 解决方案 |
|---|---|---|
| SQL注入 | 参数拼接SQL语句导致数据库泄露 | 使用参数化查询/ORM |
| XSS攻击 | 恶意脚本通过参数注入页面 | 输入过滤+输出编码 |
| CSRF攻击 | 伪造用户身份提交请求 | 添加CSRF Token校验 |
| 参数篡改 | 修改URL或表单参数越权访问 | 服务端权限校验 |
3.2 必做的参数校验清单
- 类型检查:数字参数确保是有效数字
- 长度限制:防止超长字符串攻击
- 格式验证:邮箱、手机号等符合规范
- 业务规则:订单ID是否属于当前用户
- 敏感词过滤:防止存储XSS攻击
Node.js校验示例:
javascript复制const { body, validationResult } = require('express-validator');
app.post('/register',
body('username').isLength({ min: 3 }).trim().escape(),
body('email').isEmail().normalizeEmail(),
body('age').isInt({ min: 18 }),
(req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
// 处理合法请求...
}
);
4. 高级技巧与性能优化
4.1 GET请求缓存策略
合理利用HTTP缓存可以显著提升性能:
http复制GET /api/products?category=electronics HTTP/1.1
Host: api.example.com
Cache-Control: max-age=3600
服务端响应时设置:
Cache-Control: public, max-age=3600(缓存1小时)ETag指纹验证(资源变更时失效)
4.2 POST请求的幂等性设计
对于支付等关键操作,即使网络超时也要保证不会重复执行:
javascript复制// 客户端生成唯一ID
const idempotencyKey = crypto.randomUUID();
fetch('/api/payments', {
method: 'POST',
headers: {
'Idempotency-Key': idempotencyKey
},
body: JSON.stringify(paymentData)
});
服务端需要:
- 存储已处理的key
- 重复请求返回相同响应
- 设置合理过期时间(如24小时)
4.3 大文件上传优化方案
当需要上传大文件时,传统POST可能超时:
- 分片上传(chunked upload)
- 断点续传(resume upload)
- 前端压缩(client-side compression)
- 进度监控(upload progress)
分片上传示例:
javascript复制const chunkSize = 5 * 1024 * 1024; // 5MB
const file = input.files[0];
const chunks = Math.ceil(file.size / chunkSize);
for (let i = 0; i < chunks; i++) {
const chunk = file.slice(i * chunkSize, (i + 1) * chunkSize);
const formData = new FormData();
formData.append('file', chunk);
formData.append('chunkIndex', i);
formData.append('totalChunks', chunks);
await axios.post('/upload-chunk', formData);
}
5. 调试技巧与问题排查
5.1 常用调试工具对比
| 工具 | 适用场景 | 特色功能 |
|---|---|---|
| Chrome DevTools | 前端调试 | 网络请求查看、重发 |
| Postman | API测试 | 环境变量、测试脚本 |
| curl | 命令行测试 | 快速验证接口 |
| Wireshark | 网络抓包 | 原始HTTP报文分析 |
5.2 常见错误代码处理
400 Bad Request
- 检查参数是否缺失或格式错误
- 验证Content-Type是否匹配body格式
401 Unauthorized
- 确认认证头(Authorization)是否正确
- 检查token是否过期
413 Payload Too Large
- 减少POST数据量
- 启用分片上传
429 Too Many Requests
- 降低请求频率
- 实现指数退避重试机制
实战案例:处理限流
javascript复制async function fetchWithRetry(url, options, retries = 3) {
try {
const response = await fetch(url, options);
if (response.status === 429 && retries > 0) {
const delay = Math.pow(2, 4 - retries) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
return fetchWithRetry(url, options, retries - 1);
}
return response;
} catch (error) {
if (retries > 0) {
return fetchWithRetry(url, options, retries - 1);
}
throw error;
}
}
在实际项目中,我习惯为所有API请求封装统一的错误处理层,自动处理网络异常、超时重试、错误提示等通用逻辑。这样可以保持业务代码的简洁性,同时确保整个应用具有一致的错误处理体验。
