How do @RequestHeader and @CookieValue work, and how do they differ from @RequestParam?
answer
- Header / cookie source, same rules as RequestParam
- header names case-insensitive
- bulk: Map / MultiValueMap / HttpHeaders
- @CookieValue -> value, or full jakarta Cookie object
- missing required -> 400 (MissingRequestHeader/CookieException)
basics
~20 s@RequestHeader binds an HTTP request header (e.g. Accept-Language, Authorization) to a method parameter; @CookieValue binds a single cookie's value by name. Both support required, defaultValue, and type conversion, just like @RequestParam — they only differ in WHERE they read from.
solid answer
~40 s@RequestHeader reads an HTTP request header by name into a parameter — @RequestHeader("User-Agent") String ua — with type conversion and the same required/defaultValue attributes as @RequestParam; header names are case-insensitive. You can bind all headers at once into a Map<String,String>, MultiValueMap<String,String>, or HttpHeaders. @CookieValue reads a single cookie's value by name; declare the parameter as jakarta.servlet.http.Cookie to get the whole cookie object instead of just its value. All four annotations (@RequestParam, @PathVariable, @RequestHeader, @CookieValue) share the same argument-resolver family and the same required-by-default semantics, differing only in the source: query/form params, URI path segments, headers, and cookies respectively. Common uses: reading Accept-Language, X-Request-Id/correlation ids, a custom API-key header, or a session/tracking cookie.
code
java · 9 lines@GetMapping("/whoami")
public Info whoami(
@RequestHeader("Accept-Language") String lang,
@RequestHeader(value = "X-Request-Id", required = false) String reqId,
@RequestHeader HttpHeaders allHeaders, // bulk bind
@CookieValue(value = "theme", defaultValue = "light") String theme,
@CookieValue("SESSION") Cookie sessionCookie) { // full Cookie object
return new Info(lang, reqId, theme, sessionCookie.getMaxAge());
}go deeper
Knows @RequestHeader reads headers and @CookieValue reads a cookie.
Explains shared required/defaultValue semantics and bulk-binding options.
Knows the Cookie-object vs value nuance, multi-value headers, and the missing -> 400 mapping.
Reasons about when to read headers directly vs delegate to Spring Security / filters, and correlation-id patterns.
Every HTTP request carries several distinct channels of input: the URI path, the query string, headers, cookies, and the body. Spring MVC gives you a dedicated binding annotation per channel, all resolved by the same underlying machinery (Named-value argument resolvers), so they share attributes and behavior. **@RequestHeader** binds one request header value to a parameter: ```java @GetMapping("/x") public String h(@RequestHeader("Accept-Language") String lang, @RequestHeader(value = "X-Request-Id", required = false) String reqId) { ... } ``` - Header names are **case-insensitive** (HTTP semantics), so "Accept-Language" and "accept-language" both work. - Supports the same `required` (default true), `defaultValue`, and Optional/nullable handling as @RequestParam. A missing required header -> MissingRequestHeaderException -> HTTP 400. - Type conversion applies: `@RequestHeader("Content-Length") long len` converts the string to a long; a comma-separated header can bind to a `List<String>` or array. - **Bulk binding**: declare `@RequestHeader Map<String,String> headers`, `@RequestHeader MultiValueMap<String,String> headers` (to preserve multiple values per header), or `@RequestHeader HttpHeaders headers` to receive every header at once. **@CookieValue** binds a single cookie by name: ```java @GetMapping("/y") public String c(@CookieValue("JSESSIONID") String sessionId, @CookieValue(value = "theme", defaultValue = "light") String theme) { ... } ``` - By default you get the cookie's **value** (a String, subject to conversion). If you declare the parameter type as `jakarta.servlet.http.Cookie`, Spring gives you the full Cookie object (name, value, path, maxAge, etc.). - Same required/defaultValue semantics; a missing required cookie -> MissingRequestCookieException -> 400. **How they differ from @RequestParam**: purely the *source*. - @RequestParam: query-string params or form/multipart body fields. - @PathVariable: a segment of the URI path template. - @RequestHeader: an HTTP request header. - @CookieValue: a Cookie header entry (one named cookie). All four share: automatic type conversion via ConversionService, required=true default, defaultValue support (a String that gets converted), Optional/nullable handling, and explicit-name attributes for when parameter names aren't compiled in. **Gotchas**: - Don't hand-parse the Cookie header — use @CookieValue. - Reading Authorization manually is usually a smell; prefer Spring Security. But @RequestHeader("Authorization") is fine for simple custom schemes/tests. - Headers can legitimately appear multiple times; bind to List or MultiValueMap if you need all values, otherwise you may only see the first/joined value. - Missing header/cookie is 400 by default — set required=false or a defaultValue for optional metadata like correlation ids.
- How do you capture ALL request headers, including headers that appear multiple times?Bind a @RequestHeader parameter of type MultiValueMap<String,String> (preserves multiple values per header name) or HttpHeaders. A plain Map<String,String> collapses to a single value per name.
- What happens to a required @CookieValue when the cookie isn't sent?Spring throws MissingRequestCookieException, which maps to HTTP 400. Set required=false or provide a defaultValue to treat it as optional.
saying these in an interview costs you the question
- Claiming header names are case-sensitive.
- Thinking @CookieValue always returns a Cookie object (it returns the value unless you declare the param type as Cookie).
- Manually parsing the Cookie or Authorization header when the annotations exist.