前端说 token 已经放进请求头了,后端 getHeader 取出来是 null。日志一打,请求确实到了,头却少那一个。常见原因是网关把带下划线的头丢了,或者前端根本没设在 headers 上。
原生写法就三个方法
String token = request.getHeader(HttpHeaders.AUTHORIZATION); Enumeration<String> names = request.getHeaderNames();头名不区分大小写,Authorization 和 authorization 取到的是同一个值。经过多层代理时同名头会有多个,比如 X-Forwarded-For,这时候得用 getHeaders 拿枚举,再逐个读。
取不到值时,第一个动作是把所有头名打出来看一眼,别先怀疑代码。
Spring 里用注解更短
public Result list(@RequestHeader(HttpHeaders.AUTHORIZATION) String token) { }参数名和头名不一致就填 value,要求可以不传就把 required 设成 false。想一次拿到全部,注入 HttpHeaders,或者用 Map<String, String> 接,注意 Map 里存的是第一个值,多值场景会丢。
四个排查方向
- 先看 getHeaderNames 的输出,确认头究竟有没有到服务端。
- Nginx 默认会丢弃名字带下划线的头,需要显式打开才能透传。
- 跨域请求里的自定义头会先发预检,后端没允许对应的头,业务方法根本不会执行。
- 前端把参数塞进了查询串而不是 headers,后端自然读不到。
别把头当身份
头是客户端随便写的。用户 ID、角色这类信息不能直接信任请求头,除非前面有可信网关统一覆盖并校验过。写个 uid 头就按它查权限,等于把越权接口摆到公网上。
判断:取值统一用常量避免拼错,排查从打印全部头名开始,涉及鉴权的头必须有服务端校验兜底。