Java
Spring Boot
Request Headers
Null Value
Web Development

Spring Boot request header return null value

Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms

Introduction

When @RequestHeader returns null in Spring Boot, the header either was not sent by the client, was misspelled, or was stripped by a proxy or load balancer before reaching your application. Spring is case-insensitive for header names, so the issue is almost always about the header being absent rather than a casing mismatch. The fix depends on which scenario applies: make the header optional with required = false, check your client request, or inspect your reverse proxy configuration.

How @RequestHeader Works

java
1@RestController
2public class MyController {
3
4    @GetMapping("/api/data")
5    public String getData(@RequestHeader("X-Custom-Token") String token) {
6        return "Token: " + token;
7    }
8}

If the X-Custom-Token header is missing from the request, Spring throws MissingRequestHeaderException (400 Bad Request) by default — not null. You only get null when you explicitly make the header optional.

Cause 1: Header Not Sent by Client

The most common cause. Verify the header is actually being sent:

bash
1# Test with curl — include the header explicitly
2curl -H "X-Custom-Token: abc123" http://localhost:8080/api/data
3
4# Without the header — triggers 400 error
5curl http://localhost:8080/api/data

In JavaScript fetch calls, headers are often missing due to typos:

javascript
1// WRONG — header name typo
2fetch('/api/data', {
3    headers: { 'X-Custm-Token': 'abc123' }  // missing 'o'
4});
5
6// CORRECT
7fetch('/api/data', {
8    headers: { 'X-Custom-Token': 'abc123' }
9});

Cause 2: Header Made Optional Without Default

java
1// This returns null when the header is missing
2@GetMapping("/api/data")
3public String getData(
4        @RequestHeader(value = "X-Custom-Token", required = false) String token) {
5    // token is null if header is absent
6    return "Token: " + token;  // "Token: null"
7}
8
9// Fix: provide a default value
10@GetMapping("/api/data")
11public String getData(
12        @RequestHeader(value = "X-Custom-Token", defaultValue = "none") String token) {
13    return "Token: " + token;  // "Token: none" when absent
14}

Cause 3: Proxy or Load Balancer Stripping Headers

Reverse proxies (Nginx, Apache, AWS ALB) can strip or rename custom headers:

nginx
1# Nginx — custom headers with underscores are dropped by default
2# Fix: enable underscores in headers
3server {
4    underscores_in_headers on;
5
6    location / {
7        proxy_pass http://localhost:8080;
8        proxy_set_header X-Custom-Token $http_x_custom_token;
9    }
10}

AWS Application Load Balancer strips headers with underscores by default. Use hyphens instead: X-Custom-Token instead of X_Custom_Token.

Cause 4: CORS Preflight Dropping Headers

Browser CORS preflight requests (OPTIONS) do not include custom headers. If your controller handles OPTIONS requests, the header will be absent:

java
1@Configuration
2public class CorsConfig implements WebMvcConfigurer {
3    @Override
4    public void addCorsMappings(CorsRegistry registry) {
5        registry.addMapping("/api/**")
6                .allowedOrigins("http://localhost:3000")
7                .allowedHeaders("X-Custom-Token", "Content-Type")
8                .allowedMethods("GET", "POST", "PUT", "DELETE");
9    }
10}

The allowedHeaders configuration must include your custom header name, or the browser will not send it in the actual request.

Cause 5: Using HttpServletRequest Directly

java
1@GetMapping("/api/data")
2public String getData(HttpServletRequest request) {
3    // getHeader() returns null if header is absent — no exception
4    String token = request.getHeader("X-Custom-Token");
5
6    if (token == null) {
7        return "Header not found";
8    }
9    return "Token: " + token;
10}

HttpServletRequest.getHeader() always returns null for missing headers without throwing an exception, unlike @RequestHeader with required = true.

Debugging Headers

java
1@GetMapping("/api/debug")
2public Map<String, String> debugHeaders(HttpServletRequest request) {
3    Map<String, String> headers = new HashMap<>();
4    Enumeration<String> headerNames = request.getHeaderNames();
5    while (headerNames.hasMoreElements()) {
6        String name = headerNames.nextElement();
7        headers.put(name, request.getHeader(name));
8    }
9    return headers;  // Returns all headers as JSON
10}

Call this endpoint to see exactly which headers arrive at your application.

Using Optional for Nullable Headers

java
1@GetMapping("/api/data")
2public String getData(
3        @RequestHeader(value = "X-Custom-Token", required = false)
4        Optional<String> token) {
5    return token.map(t -> "Token: " + t)
6                .orElse("No token provided");
7}

Common Pitfalls

  • Assuming null means the annotation failed: @RequestHeader with required = true (default) throws a 400 error, not null. If you see null, you made the header optional somewhere.
  • Underscore in header names: Nginx drops headers with underscores (X_Custom_Token) by default. Use hyphens (X-Custom-Token) or enable underscores_in_headers on.
  • Testing with browser DevTools: The browser may not send custom headers on GET requests unless you use fetch() or XMLHttpRequest. Direct URL bar navigation sends no custom headers.
  • Case sensitivity confusion: HTTP header names are case-insensitive per the spec, and Spring handles this correctly. x-custom-token and X-Custom-Token are the same header.
  • Spring Security intercepting requests: If Spring Security is configured, it may reject requests before they reach your controller. Check your security filter chain if headers seem to disappear.

Summary

  • @RequestHeader throws 400 by default for missing headers — use required = false to get null instead
  • Always verify the client is actually sending the header (use curl or browser DevTools)
  • Reverse proxies often strip custom headers with underscores — use hyphens
  • Add allowedHeaders in CORS configuration for custom headers from browsers
  • Use HttpServletRequest.getHeader() or Optional<String> for graceful null handling
  • Create a debug endpoint to inspect all incoming headers when troubleshooting

Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms