Content-Type
Correct parsing and rendering of an HTTP message body depends on knowing the media type. The HTTP Content-Type request and response header declares that type.
Usage
The Content-Type header tells the client (or server, for request bodies) the media type of the enclosed content. The media type determines how the recipient parses and renders the body. Without this header, clients resort to MIME sniffing, which introduces security risks and inconsistent behavior.
A server refusing a request because of its Content-Type answers 415, the status code paired with this header on the request side.
A media type consists of a top-level type and a subtype separated by a slash, optionally followed by parameters. The Accept request header works alongside Content-Type during content negotiation, letting the client express preferred media types before the server selects one.
Servers and intermediaries sometimes apply Content-Encoding (such as gzip or br) before transmission. The Content-Type header always describes the original media type before encoding, not the encoded format.
The MIME-Version header traces back to the email origins of MIME types and appears in some HTTP messages, though HTTP does not require the header for media type processing.
Parameters
media-type
The media type value follows the type/subtype format
registered with IANA. Common types include text/html,
application/json, image/png, and
application/octet-stream. A
complete registry
is maintained by IANA.
charset
The charset parameter specifies the character encoding of
text-based media types. UTF-8 is the dominant encoding on
the web.
Content-Type: text/html; charset=UTF-8
Charset names match case-insensitively, so utf-8
and UTF-8 are the same value. application/json
defines no charset parameter at all: JSON is UTF-8
by definition, and the widely sent
application/json; charset=utf-8 carries a
parameter compliant recipients ignore. Recipients
also ignore any parameter they do not recognize,
and the q weight belongs to Accept,
never to Content-Type.
boundary
The boundary parameter is required for multipart/* media
types. The boundary string separates each part of the
multipart body. The boundary value must not appear within any
of the body parts.
Content-Type: multipart/form-data; boundary=----FormBoundary
Example
A server returns an HTML page with UTF-8 encoding. The browser uses the media type to render the content as a web page and the charset to decode the text correctly.
Content-Type: text/html; charset=UTF-8
An API returns a JSON response. The application/json media
type instructs the client to parse the body as JSON.
Content-Type: application/json
An API error response uses the
application/problem+json media type to signal a
structured problem details payload.
Content-Type: application/problem+json
A CDN converts an HTML page to Markdown on the fly
when the client sends Accept: text/markdown. The
response carries text/markdown as the content type,
signaling the body is Markdown rather than HTML.
Content-Type: text/markdown; charset=utf-8
A file upload uses multipart/form-data with a boundary
string separating the form fields and file data within the
request body.
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
A server delivers a binary file download. The
application/octet-stream type signals raw binary data,
often paired with a
Content-Disposition header set to
attachment.
Content-Type: application/octet-stream
A multipart/byteranges response delivers multiple byte
ranges from a single resource. Each part has its own
Content-Type and Content-Range header.
Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES
Server configuration
Web servers map file extensions to media types through a shipped mapping file, and the shipped maps lag the web platform in different ways.
nginx's mime.types includes application/wasm and
font/woff2 in current releases, while packages
built from older release lines predate the wasm
entry. .mjs and .webmanifest appear in no nginx
release, so both fall through to default_type,
application/octet-stream in the stock
configuration. Apache's map covers application/wasm
and assigns text/javascript to both .js and
.mjs, and an unmapped extension on Apache produces
a response without any Content-Type header at
all.
Two consumers enforce the type strictly. Streaming
WebAssembly compilation through
WebAssembly.instantiateStreaming() requires
application/wasm with no parameters,
and even an appended charset rejects the module with
a TypeError. JavaScript module scripts load only
under a JavaScript MIME type such as
text/javascript or
application/javascript, with no sniffing fallback.
Classic scripts tolerate a wrong type unless
X-Content-Type-Options
enforces nosniff, and module scripts get checked
regardless. The practical result on stock nginx: a
.js module works while the same code as .mjs
arrives as application/octet-stream and the
browser blocks the import.
Adding the missing mappings closes the gap. In
nginx the block belongs at the http level next to
include mime.types;, since a types block at the
server or location level replaces the inherited
mapping table instead of extending the table:
types {
application/wasm wasm;
text/javascript mjs;
application/manifest+json webmanifest;
}
In Apache:
AddType application/wasm .wasm
AddType text/javascript .mjs
AddType application/manifest+json .webmanifest
The .webmanifest mapping is a correctness fix
rather than a breakage fix. The registered type is
application/manifest+json, and browsers accept a
manifest under any JSON media type.
Troubleshooting
Rendering failures and parsing errors often trace back to a missing or incorrect Content-Type header.
Missing
charsetparameter causes garbled text. Browsers fall back to a default encoding (windows-1252 in most locales) when no charset is declared. Non-ASCII characters appear as mojibake. Add the charset parameter explicitly:Content-Type: text/html; charset=UTF-8. In nginx:charset utf-8;In Apache:
AddDefaultCharset UTF-8Browser applies MIME sniffing despite a correct Content-Type. Browsers sometimes ignore the declared type and sniff the body content to determine the type. This behavior creates XSS attack vectors when user-uploaded content is served as HTML. Add the X-Content-Type-Options header set to
nosniffto block MIME sniffing:X-Content-Type-Options: nosniffAPI returns
text/htmlinstead ofapplication/json. Clients parsing JSON from an API receive HTML error pages or framework default responses. This happens when an error handler or reverse proxy intercepts the response and replaces the body without updating the Content-Type. Check the full response chain: origin server, application framework, reverse proxy, and CDN. In Express.js, callingres.json()sets the correct header automatically. In Django, returnJsonResponseinstead ofHttpResponse.Multipart boundary mismatch breaks file uploads. The
boundarystring declared in the Content-Type header must match the delimiter used in the request body. A mismatch causes the server to fail parsing the multipart body. Inspect the raw request in DevTools Network tab under the Headers and Payload sections. Avoid setting the boundary manually when usingfetch()orXMLHttpRequestwithFormDataobjects. The browser generates the correct boundary automatically when the Content-Type header is omitted from the request.Framework default Content-Type overrides an explicit setting. Some frameworks set Content-Type after the application code runs. Middleware in Express.js, Django, or Spring Boot may reset the header. Check middleware execution order. In Express.js, ensure
res.type()orres.set('Content-Type', ...)is called after all middleware that modifies headers.Diagnosing Content-Type issues with DevTools. Open the browser DevTools Network tab, select the request, and inspect the Response Headers section for the Content-Type value. Compare the declared type with the actual body content shown in the Response or Preview tab. Use
curl -sS -o /dev/null -D- https://example.re/api/datato check headers from the command line without browser interference.
See also
- RFC 9110: HTTP Semantics - Content-Type
- Accept
- HTTP media types
- Content negotiation
- Content-Encoding
- Content-Disposition
- MIME-Version
- Problem details
- HTTP headers