Spring Boot中验证请求头日期格式的正确方法(注解无效问题)
我有如下Spring控制器代码:
@RestController @RequestMapping("/initiatiation-task/v1") public class LoginInitiationTaskController { private final LoginInitiationTaskService loginInitiationTaskService; @PostMapping("/login") public ResponseEntity<InitiateLoginResponse> initiateLogin( @Valid @RequestHeader("Date") @DateTimeFormat(pattern = "EEE, dd MMM yyyy HH:mm:ss Z") ZonedDateTime date) { // ... } }
我需要验证请求头中的日期格式,但上述配置无法生效。我还尝试了用@JsonFormat注解:
@JsonFormat( pattern = "EEE, dd MMM yyyy HH:mm:ss Z", timezone="GMT") ZonedDateTime date
当发送带有格式为Sun, 01 Jan 2023 06:49:53 GMT的请求头时,Spring抛出异常:
org.springframework.web.method.annotation.MethodArgumentTypeMismatchException:
Failed to convert value of type 'java.lang.String' to required type
'java.time.ZonedDateTime'; Failed to convert from type
[java.lang.String] to type
[@org.springframework.web.bind.annotation.RequestHeader
@com.fasterxml.jackson.annotation.JsonFormat java.time.ZonedDateTime]
for value 'Sun, 01 Jan 2023 06:49:53 GMT'
请问如何正确验证请求头中的日期格式?
方法一:自定义转换器(推荐)
Spring处理请求头参数时不认可@JsonFormat,而@DateTimeFormat对ZonedDateTime的支持需要配合自定义转换器。可以创建一个转换器专门处理RFC1123格式的日期转换:
- 编写自定义转换器类:
import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; @Component public class Rfc1123ZonedDateTimeConverter implements Converter<String, ZonedDateTime> { private static final DateTimeFormatter RFC_1123_FORMATTER = DateTimeFormatter.RFC_1123_DATE_TIME; @Override public ZonedDateTime convert(String source) { return ZonedDateTime.parse(source, RFC_1123_FORMATTER); } }
- 控制器方法中直接使用
@RequestHeader,无需额外格式化注解:
@PostMapping("/login") public ResponseEntity<InitiateLoginResponse> initiateLogin( @Valid @RequestHeader("Date") ZonedDateTime date) { // ... }
格式不匹配时会自动抛出DateTimeParseException,可以通过全局异常处理器统一返回错误响应。
方法二:@DateTimeFormat指定英文Locale
@DateTimeFormat默认用系统Locale,而RFC1123格式的英文星期、月份缩写需要指定英文Locale才能解析:
@PostMapping("/login") public ResponseEntity<InitiateLoginResponse> initiateLogin( @Valid @RequestHeader("Date") @DateTimeFormat(pattern = "EEE, dd MMM yyyy HH:mm:ss Z", locale = "en_US") ZonedDateTime date) { // ... }
注意:Spring Boot 2.x及以上默认已支持Java 8时间API,无需额外配置。
方法三:手动解析+自定义验证
如果需要更灵活的错误处理,可以先接收字符串类型的请求头,手动解析验证:
import javax.validation.constraints.NotBlank; import java.time.format.DateTimeParseException; @PostMapping("/login") public ResponseEntity<InitiateLoginResponse> initiateLogin( @NotBlank @RequestHeader("Date") String dateStr) { try { ZonedDateTime date = ZonedDateTime.parse(dateStr, DateTimeFormatter.RFC_1123_DATE_TIME); // 业务逻辑处理 } catch (DateTimeParseException e) { // 返回格式错误的响应 return ResponseEntity.badRequest().body(new InitiateLoginResponse("日期格式错误,请遵循RFC1123标准")); } }
内容的提问来源于stack exchange,提问作者Farhan stands with Palestine

