1. 概述
本文将系统性地介绍在 Spring 5 中如何为接口响应设置响应头(Response Header),涵盖传统非响应式(non-reactive)和响应式(reactive)两种编程模型。无论你使用的是 Spring MVC 还是 WebFlux,都能找到对应的解决方案。
核心目标是:✅ 精准控制每个接口或全局响应头,避免重复代码,同时踩坑少。
文中示例均可在 GitHub 找到完整代码,非响应式部分位于:https://github.com/baeldung/spring-rest-http,响应式部分见:https://github.com/baeldung/spring-reactive-2。
2. 非响应式接口的响应头设置
适用于 Spring MVC 场景。常见方式有三种:
- 单接口设置:使用
HttpServletResponse
或ResponseEntity
- 全局设置:通过
Filter
统一注入
2.1 使用 HttpServletResponse
最直接的方式,直接操作底层 HttpServletResponse
对象。适合简单场景,但侵入性较强。
@GetMapping("/http-servlet-response")
public String usingHttpServletResponse(HttpServletResponse response) {
response.addHeader("Baeldung-Example-Header", "Value-HttpServletResponse");
return "Response with header using HttpServletResponse";
}
⚠️ 注意:无需返回 response
对象,Spring 会自动处理输出。
2.2 使用 ResponseEntity
更推荐的方式,声明式设置,代码更清晰,且与底层 Servlet API 解耦。
@GetMapping("/response-entity-builder-with-http-headers")
public ResponseEntity<String> usingResponseEntityBuilderAndHttpHeaders() {
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("Baeldung-Example-Header",
"Value-ResponseEntityBuilderWithHttpHeaders");
return ResponseEntity.ok()
.headers(responseHeaders)
.body("Response with header using ResponseEntity");
}
✅ HttpHeaders
提供了大量便捷方法,比如 setContentType()
、setCacheControl()
等,处理常见头字段非常方便。
2.3 为所有响应添加统一响应头
如果每个接口都手动加头,那简直是灾难。正确的做法是使用 Filter
统一拦截。
@WebFilter("/filter-response-header/*")
public class AddResponseHeaderFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader(
"Baeldung-Example-Filter-Header", "Value-Filter");
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// 初始化逻辑(可选)
}
@Override
public void destroy() {
// 销毁逻辑(可选)
}
}
关键点:
@WebFilter
指定该 Filter 生效的 URL 路径。- 要让 Spring 扫描到这个 Filter,必须在主应用类上添加
@ServletComponentScan
:
@ServletComponentScan
@SpringBootApplication
public class ResponseHeadersApplication {
public static void main(String[] args) {
SpringApplication.run(ResponseHeadersApplication.class, args);
}
}
⚠️ 替代方案:如果你不想用 @WebFilter
,可以直接用 @Component
注解该 Filter 类,Spring Boot 会自动注册它,无需 @ServletComponentScan
。
3. 响应式接口的响应头设置
适用于 Spring WebFlux 场景,基于 Reactor 模型,核心对象不同,但思路一致。
3.1 使用 ServerHttpResponse
类比 HttpServletResponse
,用于直接操作响应对象。
@GetMapping("/server-http-response")
public Mono<String> usingServerHttpResponse(ServerHttpResponse response) {
response.getHeaders().add("Baeldung-Example-Header", "Value-ServerHttpResponse");
return Mono.just("Response with header using ServerHttpResponse");
}
⚠️ 注意返回类型是 Mono<String>
,但头信息在返回前已写入。
3.2 使用 ResponseEntity
与非响应式用法几乎一致,只是包装在 Mono
中返回。
@GetMapping("/response-entity")
public Mono<ResponseEntity<String>> usingResponseEntityBuilder() {
String responseHeaderKey = "Baeldung-Example-Header";
String responseHeaderValue = "Value-ResponseEntityBuilder";
String responseBody = "Response with header using ResponseEntity (builder)";
return Mono.just(ResponseEntity.ok()
.header(responseHeaderKey, responseHeaderValue)
.body(responseBody));
}
✅ 推荐方式,语义清晰,适合大多数场景。
3.3 使用 ServerResponse(函数式编程)
如果你使用 Spring 5 的函数式 Web 框架(Functional Endpoints),则需使用 ServerResponse
。
public Mono<ServerResponse> useHandler(final ServerRequest request) {
return ServerResponse.ok()
.header("Baeldung-Example-Header", "Value-Handler")
.body(Mono.just("Response with header using Handler"),String.class);
}
⚠️ 仅适用于 RouterFunction
+ HandlerFunction
模式,非注解驱动。
3.4 为所有响应式接口添加统一响应头
使用 WebFilter
,这是 WebFlux 的过滤器标准。
@Component
public class AddResponseHeaderWebFilter implements WebFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
exchange.getResponse()
.getHeaders()
.add("Baeldung-Example-Filter-Header", "Value-Filter");
return chain.filter(exchange);
}
}
✅ @Component
注解即可自动注册,无需额外扫描。
关键对象:
ServerWebExchange
:WebFlux 中的请求-响应上下文WebFilterChain
:过滤链,调用chain.filter()
继续执行
4. 总结
场景 | 推荐方式 |
---|---|
单个非响应式接口 | ✅ ResponseEntity |
全局非响应式接口 | ✅ Filter + @Component 或 @WebFilter |
单个响应式接口 | ✅ ResponseEntity (返回 Mono ) |
全局响应式接口 | ✅ WebFilter |
核心原则:
- 尽量使用声明式(如
ResponseEntity
),避免直接操作底层对象 - 全局头信息统一用 Filter/WebFilter,避免重复代码
- 函数式编程场景注意使用
ServerResponse
所有示例代码已整理至 GitHub:
掌握这些技巧,响应头设置再也不是问题。