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
也提供了一些属性来定制行为:
-
name
(或value
):- 必需属性(除非参数名匹配)。指定要绑定的请求头的名称。这是最常用的属性。
name
和value
是同义词。- 示例:
@RequestHeader(name = "Authorization") String token
。 - 注意:虽然理论上如果方法参数名与头名称(转换为驼峰式,例如
userAgent
对应User-Agent
)匹配,可能可以省略name
,但这依赖于编译时参数名保留,并且对于包含-
的标准头名称(如User-Agent
)根本行不通。因此,强烈建议始终使用name
或value
属性明确指定头名称。
-
required
:- 指定该请求头是否必须存在于请求中。
- 类型:
boolean
。 - 默认值:
true
。如果required=true
,但请求中没有该头信息,Spring MVC 会抛出MissingRequestHeaderException
异常,导致 HTTP 400 (Bad Request) 响应。 - 如果请求头是可选的,需要设置为
required = false
。
-
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 请求头 的值绑定到方法参数。- 必须 使用
name
或value
属性指定要读取的头名称(除非特殊情况,但不推荐省略)。 - 使用
required = false
使头变为可选(不存在时为null
或Optional.empty()
)。 - 使用
defaultValue = "value"
为可选头提供默认值(头不存在时生效,隐含required=false
)。 - 可以将多值头(逗号分隔)绑定到
List
或数组。 - 可以通过将
@RequestHeader
应用于Map
,MultiValueMap
或(推荐的)HttpHeaders
对象来访问所有头信息。 - 与
@RequestParam
(用于查询/表单参数)和@PathVariable
(用于路径变量)不同,@RequestHeader
专注于 HTTP Headers。