1. Background
HTTP follows a request-response model: the client sends a request first, then the server processes it and sends back a response. That response has three parts — the status line (HTTP version and status code), headers (metadata about the browser, server, or response body), and the body (the actual entity data).
In Java-based servers, response headers live in a Header attribute. There are two main ways to set them: HttpServletResponse.setHeader(name, MIME) and HttpServletResponse.addHeader(name, MIME). This post digs into how they work under the hood and what the difference actually is. The Tomcat source code referenced here is version 8.5.31.
2. How It Works Internally
3. The Difference Between setHeader and addHeader
Looking at the code, response headers fall into two categories: special attributes (Content-Type and Content-Length) and regular attributes (stored in MimeHeaderFields). All of these live in the coyote/Response class.
Looking at the implementation, setHeader creates or overwrites a value, while addHeader just appends to the queue. One important detail: when setHeader overwrites an existing attribute, it also removes all other entries with the same name from the queue. Here’s the source:
1 | // Header group |
With addHeader, you can set multiple values for the same attribute. The next question: which value do you actually get? There are two methods for reading headers — getHeader(name) and getHeaders(name):
1 | /** |
The implementation makes it clear: getHeader returns the first matching value, while getHeaders returns all values for that header name. We can verify this with a quick test:
1 | response.setHeader("set", "one"); |