React请求的Token Header在Spring Boot服务端丢失问题求助
我有一个React客户端应用,通过Axios发送HTTP GET请求至Spring Boot服务端,请求代码如下:
export const restApiGet = async (apiPath: string) => { const headers = { 'token': 'aaaa', 'postman-token': 'bbbb', }; return Axios.get(`${apiUrl}${apiPath}`, { withCredentials: true, // Include cookies in the request headers: headers } ); };
服务端收到请求后,在自定义的UserIdFilter过滤器中尝试读取token header,但获取结果为null。在Chrome中查看请求时,发现header被自动从token转换为Token,但读取Token也无法得到结果。将Chrome中的请求复制到Postman中发送,服务端能正常获取header。已在Windows的hosts文件中配置127.0.0.1指向localhost,请求也是调用localhost。尝试调整CORS配置(如下代码)后问题仍未解决,求问如何让服务端正常获取token?
Spring Boot的CORS配置代码:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") // Allow requests from any origin .allowedMethods("*") // Allow all HTTP methods (GET, POST, PUT, DELETE, etc.) .allowedHeaders("*") // Allow all headers .exposedHeaders("*") // Expose all headers .allowCredentials(true);//.allowedOriginPatterns("*"); // Allow credentials (e.g., cookies) }
自定义过滤器代码:
@Component @WebFilter public class UserIdFilter implements Filter { //TODO add filter for all response if object has userId column it must match the userId of the token private final AbstractCacheService abstractCacheService; public UserIdFilter(AbstractCacheService abstractCacheService) { this.abstractCacheService = abstractCacheService; } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; // 此处尝试读取token header但返回null }
1. 调整过滤器执行顺序
@WebFilter默认优先级较低,可能在CORS处理前就执行,导致无法读取正确的header。通过@Order注解指定顺序,让自定义过滤器在CORS过滤器之后运行:
@Component @WebFilter @Order(Ordered.LOWEST_PRECEDENCE - 10) // 确保晚于CORS过滤器执行 public class UserIdFilter implements Filter { // ... 原有代码 }
如果使用Spring Security,需确保过滤器在Security过滤器链之后执行。
2. 改用标准HTTP Header命名
非标准的单单词header(如token)可能被浏览器或代理修改大小写甚至拦截,换成符合规范的前缀命名(如x-token):
客户端修改:
export const restApiGet = async (apiPath: string) => { const headers = { 'x-token': 'aaaa', // 改为x-token 'postman-token': 'bbbb', }; return Axios.get(`${apiUrl}${apiPath}`, { withCredentials: true, headers: headers }); };
服务端读取:
String token = httpRequest.getHeader("x-token");
3. 替换CORS配置方式
WebMvcConfigurer的CORS配置可能存在覆盖不全的情况,改用CorsFilter实现更彻底的配置:
@Configuration public class CorsConfig { @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOriginPattern("*"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); config.addExposedHeader("*"); source.registerCorsConfiguration("/**", config); return new CorsFilter(source); } }
同时移除原有的WebMvcConfigurer实现类,避免配置冲突。
4. 验证客户端Header是否正确发送
在客户端添加Axios请求拦截器,确认header是否被正常携带:
Axios.interceptors.request.use(config => { console.log('请求Header:', config.headers); return config; });
如果控制台输出中没有目标header,检查是否有其他拦截器修改了请求配置,或apiUrl是否指向正确的服务端地址。
5. 排查代理或其他拦截器干扰
- 检查Spring Boot服务端是否有其他过滤器(如Spring Security过滤器)在
UserIdFilter之前执行,可能修改或移除了header。 - 若React应用使用了代理(如
setupProxy.js),需在代理配置中允许传递自定义header:
const { createProxyMiddleware } = require('http-proxy-middleware'); module.exports = function(app) { app.use( '/api', createProxyMiddleware({ target: 'http://localhost:8080', changeOrigin: true, onProxyReq: (proxyReq, req) => { // 保留客户端发送的自定义header Object.keys(req.headers).forEach(key => { proxyReq.setHeader(key, req.headers[key]); }); } }) ); };
内容的提问来源于stack exchange,提问作者Hard Worker

