HTTP Content Types: MIME Types in Web Requests
HTTP Content-Type is a header that specifies the format of data in a request or response, such as text/html or application/json.
HTTP Content-Type
The HTTP Content-Type header tells the sender and receiver what kind of data is being transferred. Without it, browsers and servers would have to guess the format of incoming data, leading to parsing errors, broken layouts, and security vulnerabilities that are straightforward to prevent.
What Is a Content-Type
Content-Type is an HTTP header that identifies the media type, also called the MIME type, of the data being sent in an HTTP message body. It appears in both requests, when a client sends form data or a JSON payload to a server, and in responses, when a server returns HTML, an image, API data, or any other resource.
The value of a Content-Type header consists of a primary type and a subtype separated by a forward slash, such as text/html or application/json. It can also include optional parameters after a semicolon, most commonly the character encoding such as charset=UTF-8 for text-based content.
POST /api/users HTTP/1.1
Content-Type: application/json
{"name": "Alice", "email": "alice@example.com"}
HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
<!DOCTYPE html>
<html>...</html>
Common MIME Types
MIME types are organised into categories. The part before the slash indicates the general category such as text, image, audio, video, or application. The part after the slash specifies the exact format. Here are the most commonly encountered MIME types in web development.
| MIME Type | Used For |
|---|---|
| text/html | HTML web pages returned by web servers and rendered by browsers |
| text/css | CSS stylesheets. If served with the wrong type, browsers will refuse to apply the styles. |
| text/javascript | JavaScript files. The formerly used application/javascript is now deprecated in favour of this type. |
| text/plain | Plain unformatted text with no special rendering instructions |
| application/json | JSON data, the standard format for REST API request and response bodies |
| application/xml | XML data used in SOAP APIs, RSS feeds, and legacy enterprise integrations |
| application/x-www-form-urlencoded | Standard HTML form submissions where field names and values are URL-encoded in the request body |
| multipart/form-data | Form submissions that include file uploads, where each field is sent as a separate part |
| image/jpeg | JPEG compressed images, commonly used for photographs |
| image/png | PNG images with lossless compression, commonly used for graphics and screenshots |
| image/webp | WebP images offering superior compression compared to JPEG and PNG for most use cases |
| image/svg+xml | SVG vector images that scale without quality loss, commonly used for icons and illustrations |
| image/gif | GIF images supporting animation, though largely replaced by video formats for animated content |
| application/octet-stream | Generic binary data with an unknown or unspecified format. Browsers typically trigger a file download for this type. |
| application/pdf | PDF documents, which browsers can render inline or prompt to download depending on settings |
| audio/mpeg | MP3 audio files used for music and podcasts |
| video/mp4 | MP4 video files, the most widely supported video format for web delivery |
| font/woff2 | Web Open Font Format 2, the preferred format for web fonts due to its small file size |
Content-Type vs the Accept Header
Content-Type and Accept are companion headers that together enable content negotiation, a process where the client and server agree on the format of the data being exchanged. They travel in opposite directions and serve opposite purposes.
| Header | Direction | Meaning | Example |
|---|---|---|---|
| Content-Type | Sent by whoever is sending a body, whether client or server | Declares the format of the data included in the current message body | Content-Type: application/json |
| Accept | Sent by the client in requests | Declares the formats the client is able to process in the response | Accept: application/json, text/html |
When a client sends a request with Accept: application/json, it is telling the server it prefers a JSON response. The server reads this header and, if it supports JSON, responds with Content-Type: application/json in the response. If the server cannot produce the requested format, it returns a 406 Not Acceptable status code. This negotiation allows a single API endpoint to serve different formats to different clients without requiring separate URLs.
The charset Parameter
For text-based content types, the Content-Type header should include a charset parameter specifying the character encoding. Without it, browsers may use a default encoding that produces garbled text for non-ASCII characters.
Content-Type: text/html; charset=UTF-8
Content-Type: text/plain; charset=UTF-8
Content-Type: application/json; charset=UTF-8
UTF-8 is the correct and universally recommended character encoding for all text-based web content. It supports every character in the Unicode standard and is the default encoding assumed by the JSON specification, so including charset=UTF-8 on application/json responses is technically redundant but harmless and occasionally helpful for compatibility with older parsers.
Why Content-Type Matters for Security
When a Content-Type header is missing or incorrect, browsers may attempt to determine the format by examining the content itself, a behaviour called MIME sniffing. This can create a serious security vulnerability. If an attacker uploads a file containing HTML or JavaScript but with a harmless-looking filename, and the server serves it without a Content-Type header, some browsers may sniff the content, determine it looks like HTML, and execute it as a web page in the context of your domain. This can lead to cross-site scripting attacks.
The X-Content-Type-Options: nosniff response header instructs browsers to strictly follow the declared Content-Type and never attempt to sniff the format. It should be included on all responses, particularly those serving user-uploaded content.
Content-Type: text/html; charset=UTF-8
X-Content-Type-Options: nosniff
Content-Type in Form Submissions
HTML forms can submit data using two different encoding formats, and the Content-Type header determines which one is used. The default is application/x-www-form-urlencoded, which encodes field names and values as URL-encoded key-value pairs in the request body. This works well for simple text fields but cannot handle binary data or file uploads.
When a form includes a file input, the encoding must be changed to multipart/form-data by setting the enctype attribute on the form element. This format splits the request body into multiple parts, each with its own headers, allowing binary file data to be transmitted alongside text fields without encoding issues.
<form method="POST" action="/upload" enctype="multipart/form-data">
<input type="text" name="username">
<input type="file" name="avatar">
<button type="submit">Upload</button>
</form>
Frequently Asked Questions
- What happens if the Content-Type header is wrong or missing?
The consequences depend on the mismatch. A CSS file served astext/plainwill not be applied by the browser because browsers refuse to use stylesheets served with the wrong MIME type. A JSON response declared astext/htmlmay cause client parsers to fail or produce unexpected results. A JavaScript file served with an incorrect type may be blocked by the browser's strict MIME type checking. Always set Content-Type accurately to match the actual format of the data being sent. - What is the difference between application/json and text/json?
application/jsonis the correct and officially registered MIME type for JSON data, defined in RFC 8259.text/jsonis non-standard and not recognised by most parsers and frameworks. Always useapplication/jsonfor REST API responses and request bodies. Using a non-standard type can cause parsing failures in HTTP clients, CDNs, and API gateways that validate content types. - Do GET requests need a Content-Type header?
No. Content-Type is only relevant when a message includes a body. GET and HEAD requests typically have no body, so there is nothing to declare a type for and the header should be omitted. Content-Type is required on requests that include a body such as POST, PUT, and PATCH, and on all responses that return data in the body. - Why does my browser download a file instead of displaying it?
When a server responds withContent-Type: application/octet-streamor includes aContent-Disposition: attachmentheader, the browser treats the response as a file to be saved rather than content to be rendered. If you want the browser to display a file inline, ensure the response uses the correct MIME type for the content, such asapplication/pdffor PDFs orimage/jpegfor images, and omit the Content-Disposition header or set it toinline. - Can a single endpoint return different Content-Types?
Yes, through content negotiation. The client includes anAcceptheader in the request specifying which formats it can process. The server inspects this header and responds with the most appropriate format it supports, declaring the chosen type in theContent-Typeresponse header. For example, a browser requesting a page might sendAccept: text/htmlwhile an API client sendsAccept: application/json. The server can detect this and return the same data in the appropriate format for each client from the same URL.
Conclusion
Content-Type is a small but critical header that prevents parsing errors, broken layouts, and security vulnerabilities across every HTTP interaction. Setting it accurately on all API responses, form submissions, and static file deliveries is a fundamental web development practice that costs nothing and prevents a wide range of problems. Always pair it with X-Content-Type-Options: nosniff to prevent MIME sniffing attacks, use charset=UTF-8 for all text-based responses, and use the Accept header to enable content negotiation where multiple formats are needed. See also HTTP headers and REST APIs for related guidance on building well-configured web services.
