女生做蛋糕甜品屋宝宝
105.50M · 2026-04-17
在一次微服务调用中,我遇到了一个非常诡异的问题:
远程调用失败:
HTTP 400 Bad Request
<!doctype html><html>....
排查日志发现,请求是这样发出的:
GET /dataTagEntityRelation/tagInfoByEntityId
?tagType=Table
&entityIds=1
&entityIds=2
&entityIds=3
&entityIds=4
...
&entityIds=1000+
参数是一个 List<String> entityIds,通过 Feign 的 @SpringQueryMap 自动展开成 URL 参数。
结果:请求直接 400,Controller 根本没进
@GetMapping("/dataTagEntityRelation/tagInfoByEntityId")
R<TagInfoByEntityIdVO> tagInfoByEntityId(@SpringQueryMap TagInfoByEntityIdDTO dto);
public class TagInfoByEntityIdDTO {
List<String> entityIds;
String tagType;
}
GET /tagInfoByEntityId?entityIds=1&entityIds=2&entityIds=3&...entityIds=1000
但服务器实现有!
maxHttpHeaderSize = 8KB
large_client_header_buffers 4 8k;
GET /xxx?entityIds=1&entityIds=2&... HTTP/1.1
Host: xxx
User-Agent: xxx
URL 属于 请求行(request line)
请求行属于 HTTP Header
Header 有大小限制
超限直接拒绝请求
返回 400 Bad Request
流程是这样的:
网关 / Tomcat Connector 层
↓
URL 长度检测
↓
超限
↓
直接返回 400
↓
SpringMVC / Controller 完全没机会执行
所以你看到的是 HTML 400 页面,而不是业务异常 JSON。
理论上语义正确的是:
414 URI Too Long
但现实是:
| 组件 | 返回 |
|---|---|
| Tomcat | 400 |
| Nginx | 400 |
| 网关 | 400 |
实现层通常统一返回 400(Bad Request)
GET + List 参数
GET + DTO
GET + 批量 ID
GET + SpringQueryMap
POST + JSON Body
DTO 承载 List
批量查询统一 POST
public class TagInfoByEntityIdDTO {
private String tagType;
private List<Long> entityIds;
}
@PostMapping("/dataTagEntityRelation/tagInfoByEntityId")
R<TagInfoByEntityIdVO> tagInfoByEntityId(@RequestBody TagInfoByEntityIdDTO dto);
@PostMapping("/tagInfoByEntityId")
public R<TagInfoByEntityIdVO> tagInfoByEntityId(@RequestBody TagInfoByEntityIdDTO dto) {
return R.ok(service.tagInfoByEntityId(dto));
}
POST /tagInfoByEntityId
Content-Type: application/json
{
"tagType": "Table",
"entityIds": [1,2,3,4,5,6,7,...]
}
GET /tagInfoByEntityId?entityIds=1&entityIds=2&...entityIds=1000
POST /tagInfoByEntityId
Body: JSON
不要用 GET 运大数据
看到 GET + List 参数 = 架构风险
看到 GET + DTO = 架构风险
看到 GET + 批量 ID = 架构风险
这类问题不是代码 bug,是协议认知问题。
一旦理解 HTTP 报文结构和服务器实现机制,这类坑以后基本不会再踩。
系统越大,越要遵守协议设计规范,而不是“能跑就行”。