Request headers
The invisible instructions
We have seen headers in almost every lesson so far. They showed up in requests, in responses, and we quickly explained what a few of them do. But headers are doing a lot more work than we have given them credit for. They carry the instructions that make HTTP actually work: who is making the request, what format they want, what credentials they have, what browser they are using. This lesson goes deeper into the headers the client sends.
Content-Type
This one comes first because getting it wrong causes the most confusion. Content-Type tells the server the format of the request body. It is only needed on requests that have a body (POST, PUT, PATCH).
Content-Type: application/json -> JSON body
Content-Type: application/x-www-form-urlencoded -> Form data
Content-Type: multipart/form-data -> File uploads
Content-Type: text/plain -> Plain text What happens if you send a JSON body without Content-Type? The server receives a bunch of raw bytes and has no idea what they mean. It might try to parse them as form data and get garbage. It might reject the request entirely. Always set Content-Type when you are sending a body.
Accept
Accept is the opposite of Content-Type. Instead of telling the server what you are sending, it tells the server what you want back.
Accept: application/json -> "Send me JSON"
Accept: text/html -> "Send me HTML"
Accept: */* -> "Send me anything" If the server cannot produce the format you asked for, it could return 406 Not Acceptable. But in practice, most JSON APIs ignore the Accept header and always return JSON.
Authorization
This is how the client sends credentials. The format depends on the authentication scheme:
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9... -> JWT token
Authorization: Basic dXNlcjpwYXNz -> Base64(username:password) Bearer tokens are the most common in modern APIs. The token was issued during login, and now the client includes it on every request to prove who they are.
[!NOTE] The Authentication course covers Bearer tokens (JWTs) and session-based auth in full. This lesson explains the HTTP mechanism: the
Authorizationheader is how credentials travel from client to server.
Cookie
Cookies are key-value pairs that the server previously stored on the client. The browser sends them back automatically on every request to the same domain.
Cookie: session=abc123; theme=dark Multiple cookies are separated by ;. The server set these cookies earlier using Set-Cookie (which we will cover in the next lesson). The browser handles all of this automatically.
User-Agent
User-Agent identifies the client making the request.
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36
User-Agent: curl/7.88.1
User-Agent: my-api-client/1.0 Browsers send long, detailed strings. curl sends its version number. Your application can send whatever it wants. Servers use User-Agent for analytics, compatibility decisions, and bot detection.
Host
Host tells the server which website the request is for. A single IP address can host multiple websites, so this header resolves the ambiguity. It is required in HTTP/1.1.
Host: api.example.com
Host: api.example.com:8080 -> includes port if non-standard Other headers worth knowing
If-None-Match sends a cached ETag for conditional requests (from the Caching course). The server checks if the data has changed.
If-Modified-Since sends a timestamp for conditional requests.
Origin tells the server which site initiated the request. This is used for CORS, which we covered in the OPTIONS lesson.
Referer is the page that linked to this request. (Yes, “Referer” is misspelled. It has been misspelled since 1996, and it is too late to fix it.)
Those are the key request headers. The next lesson covers the other side: the headers the server sends back.
Exercises
Exercise 1: Use curl -H "Accept: application/json" to request JSON. Then change it to Accept: text/html. Compare the responses.
Exercise 2: Use curl -H "Authorization: Bearer tok_123" to send a token. On the server side, read the header and log it.
Exercise 3: Use curl -v and find the User-Agent header in the request. Then override it with -H "User-Agent: my-app/1.0".
Why must a POST request include a Content-Type header?