当前位置: 首页 > news >正文

Spring MVC @RequestHeader 注解怎么用?

我们来详细解释一下 Spring MVC 中的 @RequestHeader 注解。

@RequestHeader 注解的作用

@RequestHeader 注解用于将 HTTP 请求中的**请求头(Request Headers)**的值绑定到 Controller 方法的参数上。

请求头是 HTTP 请求的一部分,包含了关于请求本身、客户端、期望的响应格式等元数据信息。常见的请求头有 User-Agent(浏览器/客户端信息)、Accept(客户端可接受的内容类型)、Content-Type(请求体的类型)、Authorization(认证信息)、Accept-Language(语言偏好)以及各种自定义头(通常以 X- 开头,如 X-API-Key)。

@RequestHeader 允许我们在 Controller 方法中访问这些头信息。

基本用法

最直接的用法是指定要读取的请求头的名称,并将其值赋给方法参数。

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
public class HeaderController {// 读取 "User-Agent" 请求头@GetMapping("/show-user-agent")@ResponseBodypublic String showUserAgent(@RequestHeader("User-Agent") String userAgent) {return "User-Agent Header is: " + userAgent;}// 读取 "Accept-Language" 请求头@GetMapping("/show-language")@ResponseBodypublic String showAcceptLanguage(@RequestHeader("Accept-Language") String language) {return "Accepted Languages: " + language;}// 读取自定义请求头 "X-Custom-Header"@GetMapping("/show-custom-header")@ResponseBodypublic String showCustomHeader(@RequestHeader("X-Custom-Header") String customHeaderValue) {return "X-Custom-Header value: " + customHeaderValue;}
}

重要: HTTP 协议中请求头名称是大小写不敏感的。然而,在 @RequestHeader 注解中指定的名称("User-Agent", "Accept-Language")会与实际发送的头名称进行不区分大小写的匹配。但为了代码清晰和避免潜在问题,最好在注解中明确使用期望的、标准的头名称

@RequestHeader 的属性

@RequestParam 类似,@RequestHeader 也提供了一些属性来定制行为:

  1. name (或 value):

    • 必需属性(除非参数名匹配)。指定要绑定的请求头的名称。这是最常用的属性。
    • namevalue 是同义词。
    • 示例:@RequestHeader(name = "Authorization") String token
    • 注意:虽然理论上如果方法参数名与头名称(转换为驼峰式,例如 userAgent 对应 User-Agent)匹配,可能可以省略 name,但这依赖于编译时参数名保留,并且对于包含 - 的标准头名称(如 User-Agent)根本行不通。因此,强烈建议始终使用 namevalue 属性明确指定头名称
  2. required:

    • 指定该请求头是否必须存在于请求中。
    • 类型:boolean
    • 默认值:true。如果 required=true,但请求中没有该头信息,Spring MVC 会抛出 MissingRequestHeaderException 异常,导致 HTTP 400 (Bad Request) 响应。
    • 如果请求头是可选的,需要设置为 required = false
  3. defaultValue:

    • 当请求中没有提供该请求头时,为其提供一个默认值。
    • 类型:String。Spring 会尝试将这个字符串默认值转换为方法参数的目标类型(尽管对于Header,目标类型通常就是 String)。
    • 注意: 使用 defaultValue 隐含了 required = false 的行为。提供了 defaultValue 后,即使不显式设置 required = false,该头也不再是必需的。如果头不存在,就会使用默认值,不会抛出异常。

处理可选请求头和默认值

场景 1:请求头可选,如果不存在则为 null

import java.util.Optional;
// ...@GetMapping("/optional-header")
@ResponseBody
public String processOptionalHeader(@RequestHeader(name = "X-Optional-Info", required = false) String optionalInfo,@RequestHeader(name = "X-Another-Optional", required = false) Optional<String> anotherOptional) {String infoMessage = (optionalInfo != null) ? "X-Optional-Info: " + optionalInfo : "X-Optional-Info header is missing";String anotherMessage;if (anotherOptional.isPresent()) {anotherMessage = "X-Another-Optional: " + anotherOptional.get();} else {anotherMessage = "X-Another-Optional header is missing";}return infoMessage + "\n" + anotherMessage;
}
// 请求 /optional-header (无对应Header) -> 输出两条 "header is missing"
// 请求 /optional-header 且带 Header X-Optional-Info: hello -> 输出 "X-Optional-Info: hello" 和另一条 missing
// 请求 /optional-header 且带 Header X-Another-Optional: world -> 输出第一条 missing 和 "X-Another-Optional: world"
  • 使用 required = false,如果 Header 不存在,对应的 String 参数会是 null
  • 使用 Optional<String> (Spring 4.1+) 也可以处理可选值。

场景 2:请求头可选,如果不存在则使用默认值

@GetMapping("/theme")
@ResponseBody
public String getTheme(@RequestHeader(name = "X-Theme-Preference", defaultValue = "light") String theme) {// 如果请求中没有 X-Theme-Preference 头,theme 的值将是 "light"// 如果请求头是 X-Theme-Preference: dark,theme 的值将是 "dark"return "Using theme: " + theme;
}

处理多值请求头

有些请求头可能包含多个值(通常是逗号分隔的,如 Accept 头)。我们可以将方法参数声明为 List 或数组类型来接收所有值。

import java.util.List;
// ...@GetMapping("/accepted-types")
@ResponseBody
public String showAcceptedTypes(@RequestHeader("Accept") String[] acceptTypes) {// 如果 Accept 头是 "application/json, application/xml", acceptTypes 会是 ["application/json", "application/xml"]return "Client accepts: " + Arrays.toString(acceptTypes);
}@GetMapping("/cache-control")
@ResponseBody
public String showCacheControl(@RequestHeader("Cache-Control") List<String> cacheDirectives) {// 如果 Cache-Control 头是 "no-cache, no-store", cacheDirectives 会是 ["no-cache", "no-store"]return "Cache-Control directives: " + cacheDirectives;
}

Spring 会自动根据逗号 , 来分割头的值。

绑定所有请求头到 Map 或 HttpHeaders

如果我们想访问请求中的所有头信息,可以将 @RequestHeader 应用于 Map<String, String>MultiValueMap<String, String>HttpHeaders 对象。

import org.springframework.http.HttpHeaders;
import org.springframework.util.MultiValueMap;
import java.util.Map;
// ...@GetMapping("/all-headers-map")
@ResponseBody
public String getAllHeadersMap(@RequestHeader Map<String, String> headers) {// headers 包含所有请求头的 key-value 对 (key 是小写形式)// 注意: 如果一个头有多个值, Map 可能只保留一个return "All headers (Map): " + headers.toString();
}@GetMapping("/all-headers-multimap")
@ResponseBody
public String getAllHeadersMultiMap(@RequestHeader MultiValueMap<String, String> headers) {// MultiValueMap 可以正确处理一个头有多个值的情况 (key 是小写形式)return "All headers (MultiValueMap): " + headers.toString();
}@GetMapping("/all-headers-object")
@ResponseBody
public String getAllHeadersObject(@RequestHeader HttpHeaders headers) {// HttpHeaders 是 Spring 提供的专用对象,提供了方便的方法来访问头信息// 例如: headers.getContentType(), headers.getAcceptLanguageAsLocales(), headers.getFirst("X-Custom-Header")long contentLength = headers.getContentLength();return "All headers (HttpHeaders object). Content-Length: " + contentLength + ". Headers: " + headers.toString();
}
  • 推荐使用 HttpHeaders 对象,因为它提供了类型安全的方法来访问常见的头,并且能正确处理多值头和大小写问题。

总结

  • @RequestHeader 用于将 HTTP 请求头 的值绑定到方法参数。
  • 必须 使用 namevalue 属性指定要读取的头名称(除非特殊情况,但不推荐省略)。
  • 使用 required = false 使头变为可选(不存在时为 nullOptional.empty())。
  • 使用 defaultValue = "value" 为可选头提供默认值(头不存在时生效,隐含 required=false)。
  • 可以将多值头(逗号分隔)绑定到 List 或数组。
  • 可以通过将 @RequestHeader 应用于 Map, MultiValueMap 或(推荐的HttpHeaders 对象来访问所有头信息。
  • @RequestParam(用于查询/表单参数)和 @PathVariable(用于路径变量)不同,@RequestHeader 专注于 HTTP Headers。

相关文章:

  • 第5篇:EggJS中间件开发与实战应用
  • 【学习笔记】深入理解Java虚拟机学习笔记——第2章 Java内存区域与内存溢出异常
  • JavaScript性能优化实战之运行时性能优化
  • gRPC学习笔记记录以及整合gin开发
  • 云原生后端:构建高效、可扩展的现代后端架构
  • JVM——JVM 是如何执行方法调用的?
  • NFS 快速开始
  • React的patch流程
  • MySQL基本查询(二)
  • Python清空Word段落样式的方法
  • 【iOS】类与对象底层探索
  • 2025年- H20-Lc128-240. 搜索二维矩阵 II(矩阵)---java版
  • Qt 项目代码解释(4)
  • 【点对点协议(PPP)全解析】从原理到工程实践
  • PostgreSQL:pgJDBC 下载和安装
  • DeepSeek玄学指令大全
  • Redis TLS 加密对性能的影响分析
  • 机器学习中的学习率及其衰减方法全面解析
  • 【KWDB 创作者计划】技术解读:多模架构、高效时序数据处理与分布式实现
  • python入门
  • 中国队夺跳水世界杯总决赛首金
  • 据报特斯拉寻找新CEO,马斯克财报会议上表态:把更多时间投入特斯拉
  • 遍体鳞伤就是击不倒,这是国米老男孩最后的倔强
  • 宁波市纪委监委通报4起违反中央八项规定精神典型问题
  • “五一”假期预计全社会跨区域人员流动量超14亿人次
  • 解密62个“千亿县”:强者恒强,新兴产业助新晋县崛起