Appearance
Spring MVC @RequestHeader
注解详解 📝
概述
在 Web 开发中,HTTP 请求头(Request Headers)承载着客户端的重要信息,如浏览器类型、语言偏好、编码方式等。Spring MVC 提供了 @RequestHeader
注解,让我们能够轻松地在控制器方法中获取和使用这些请求头信息。
NOTE
@RequestHeader
是 Spring MVC 中用于绑定 HTTP 请求头到控制器方法参数的注解,它让我们能够直接访问客户端发送的头部信息。
为什么需要 @RequestHeader
? 🤔
传统方式的痛点
在没有 @RequestHeader
注解之前,获取请求头信息需要通过 HttpServletRequest
对象:
kotlin
@GetMapping("/demo")
fun handle(request: HttpServletRequest) {
// 手动从 HttpServletRequest 中获取请求头
val encoding = request.getHeader("Accept-Encoding")
val keepAlive = request.getHeader("Keep-Alive")?.toLongOrNull() ?: 0L
// 需要手动处理类型转换和空值检查
if (encoding != null) {
// 处理逻辑...
}
}
kotlin
@GetMapping("/demo")
fun handle(
@RequestHeader("Accept-Encoding") encoding: String,
@RequestHeader("Keep-Alive") keepAlive: Long
) {
// 直接使用,Spring 自动处理类型转换
println("编码方式: $encoding")
println("保持连接时间: $keepAlive 秒")
}
@RequestHeader
的优势
- 简洁性:直接在方法参数上声明,无需手动获取
- 类型安全:自动类型转换,减少类型转换错误
- 可读性:方法签名清晰表达了所需的请求头
- 维护性:集中管理请求头绑定逻辑
基本用法 🚀
简单示例
让我们通过一个实际的例子来理解 @RequestHeader
的基本用法:
kotlin
@RestController
class HeaderController {
@GetMapping("/user-info")
fun getUserInfo(
@RequestHeader("User-Agent") userAgent: String,
@RequestHeader("Accept-Language") language: String
): Map<String, Any> {
return mapOf(
"userAgent" to userAgent,
"preferredLanguage" to language,
"timestamp" to System.currentTimeMillis()
)
}
}
HTTP 请求示例
http
GET /user-info HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Accept-Encoding: gzip, deflate, br
高级用法 ⚙️
1. 自动类型转换
Spring 会自动将请求头的字符串值转换为目标类型:
kotlin
@GetMapping("/connection-info")
fun getConnectionInfo(
@RequestHeader("Keep-Alive") keepAlive: Long,
@RequestHeader("Content-Length") contentLength: Int,
@RequestHeader("X-Custom-Flag") customFlag: Boolean
) {
println("保持连接: $keepAlive 秒")
println("内容长度: $contentLength 字节")
println("自定义标志: $customFlag")
}
2. 可选请求头处理
使用可空类型或默认值处理可选的请求头:
kotlin
@GetMapping("/optional-headers")
fun handleOptionalHeaders(
@RequestHeader("Authorization") authorization: String?,
@RequestHeader(value = "X-Request-ID", defaultValue = "unknown") requestId: String,
@RequestHeader(value = "X-Debug", required = false) debug: String?
) {
println("授权信息: ${authorization ?: "未提供"}")
println("请求ID: $requestId")
println("调试模式: ${debug ?: "关闭"}")
}
TIP
使用 required = false
或 defaultValue
可以让某些请求头变为可选,避免客户端必须提供所有请求头。
3. 获取所有请求头
有时我们需要获取所有的请求头信息:
kotlin
@GetMapping("/all-headers")
fun getAllHeaders(
@RequestHeader headers: Map<String, String>
): Map<String, String> {
println("所有请求头:")
headers.forEach { (key, value) ->
println("$key: $value")
}
return headers
}
4. 使用 HttpHeaders 对象
对于更复杂的请求头操作,可以使用 HttpHeaders
:
kotlin
@GetMapping("/http-headers")
fun handleHttpHeaders(
@RequestHeader httpHeaders: HttpHeaders
) {
// 获取 Accept 头的所有值
val acceptTypes = httpHeaders.accept
// 获取自定义头
val customValues = httpHeaders["X-Custom-Header"]
// 检查是否包含某个头
val hasAuth = httpHeaders.containsKey("Authorization")
println("接受的媒体类型: $acceptTypes")
println("自定义头值: $customValues")
println("是否包含授权头: $hasAuth")
}
实际业务场景 💼
场景1:API 版本控制
kotlin
@RestController
class ApiVersionController {
@GetMapping("/api/users")
fun getUsers(
@RequestHeader(value = "API-Version", defaultValue = "v1") version: String
): List<Any> {
return when (version) {
"v1" -> getUsersV1()
"v2" -> getUsersV2()
else -> throw IllegalArgumentException("不支持的 API 版本: $version")
}
}
private fun getUsersV1(): List<Any> = listOf("用户数据 V1")
private fun getUsersV2(): List<Any> = listOf("用户数据 V2 - 增强版")
}
场景2:国际化支持
kotlin
@RestController
class I18nController {
@GetMapping("/welcome")
fun getWelcomeMessage(
@RequestHeader(value = "Accept-Language", defaultValue = "en") language: String
): Map<String, String> {
val message = when {
language.startsWith("zh") -> "欢迎使用我们的服务!"
language.startsWith("en") -> "Welcome to our service!"
language.startsWith("ja") -> "私たちのサービスへようこそ!"
else -> "Welcome to our service!"
}
return mapOf(
"message" to message,
"language" to language
)
}
}
场景3:安全认证
kotlin
@RestController
class SecurityController {
@GetMapping("/protected")
fun getProtectedData(
@RequestHeader("Authorization") authorization: String
): Map<String, Any> {
// 验证 Bearer Token
if (!authorization.startsWith("Bearer ")) {
throw IllegalArgumentException("无效的授权格式")
}
val token = authorization.substring(7) // 移除 "Bearer " 前缀
// 这里应该验证 token 的有效性
if (isValidToken(token)) {
return mapOf(
"data" to "敏感数据",
"user" to getUserFromToken(token)
)
} else {
throw IllegalArgumentException("无效的访问令牌")
}
}
private fun isValidToken(token: String): Boolean = token.isNotEmpty()
private fun getUserFromToken(token: String): String = "用户123"
}
请求头处理流程 🔃
让我们通过时序图来理解 @RequestHeader
的工作流程:
常见问题与最佳实践 💡
1. 请求头名称大小写问题
WARNING
HTTP 请求头名称是大小写不敏感的,但建议使用标准的大小写格式。
kotlin
// 这些都是等效的
@RequestHeader("content-type") contentType1: String
@RequestHeader("Content-Type") contentType2: String
@RequestHeader("CONTENT-TYPE") contentType3: String
2. 处理多值请求头
某些请求头可能包含多个值,用逗号分隔:
kotlin
@GetMapping("/accept-types")
fun handleAcceptTypes(
@RequestHeader("Accept") acceptTypes: List<String>
) {
println("客户端接受的媒体类型:")
acceptTypes.forEach { type ->
println("- $type")
}
}
3. 自定义请求头验证
kotlin
@GetMapping("/custom-validation")
fun handleCustomValidation(
@RequestHeader("X-API-Key") apiKey: String
) {
if (!isValidApiKey(apiKey)) {
throw IllegalArgumentException("无效的 API 密钥")
}
// 处理业务逻辑...
}
private fun isValidApiKey(apiKey: String): Boolean {
return apiKey.matches(Regex("^[A-Za-z0-9]{32}$"))
}
性能考虑 ⚡
避免过度使用
kotlin
// ❌ 不推荐:获取所有请求头但只使用少数几个
@GetMapping("/inefficient")
fun inefficientHandler(@RequestHeader headers: Map<String, String>) {
val userAgent = headers["User-Agent"]
// 只使用了一个请求头,但获取了所有
}
// ✅ 推荐:只获取需要的请求头
@GetMapping("/efficient")
fun efficientHandler(@RequestHeader("User-Agent") userAgent: String) {
// 直接获取需要的请求头
}
总结 📝
@RequestHeader
注解是 Spring MVC 中处理 HTTP 请求头的强大工具,它提供了:
- 简洁的语法:直接在方法参数上声明所需的请求头
- 自动类型转换:无需手动处理字符串到其他类型的转换
- 灵活的配置:支持可选参数、默认值等配置
- 多种绑定方式:支持单个值、多个值、Map 等不同的绑定方式
通过合理使用 @RequestHeader
,我们可以构建更加健壮、易维护的 Web 应用程序,有效处理客户端发送的各种请求头信息。
TIP
在实际项目中,建议结合业务需求合理使用 @RequestHeader
,避免过度获取不必要的请求头信息,以保持代码的简洁性和性能。