- Home
- HTTP Headers
- Content-Type Header: Complete Guide to MIME Types
Header
Content-Type Header: Complete Guide to MIME Types
Learn how the Content-Type header works. Understand MIME types, charset encoding, and how to set the correct content type for APIs, forms, and file uploads.
TL;DR: Specifies the media type (MIME type) of the request or response body. Essential for proper data parsing - use application/json for APIs, multipart/form-data for file uploads.
Content-Type tells the recipient what kind of data is in the message body. It’s like a label on a package—without it, the recipient doesn’t know if they’re receiving text, an image, JSON data, or a file.
What is Content-Type?
The Content-Type header specifies the media type (MIME type) of the body:
Content-Type: application/json; charset=utf-8
```text
This tells the recipient: "The body contains JSON data encoded in UTF-8."
## Syntax
```http
Content-Type: media-type; parameter=value
```text
Components:
- **media-type**: The MIME type (e.g., `text/html`, `application/json`)
- **parameters**: Optional modifiers (e.g., `charset=utf-8`, `boundary=...`)
## Common Content Types
### Text Content
| Content-Type | Use Case |
| --------------------------- | ---------------- |
| `text/html; charset=utf-8` | HTML web pages |
| `text/plain; charset=utf-8` | Plain text |
| `text/css` | CSS stylesheets |
| `text/javascript` | JavaScript files |
| `text/csv` | CSV data files |
| `text/xml` | XML documents |
### Application Data
| Content-Type | Use Case |
| -------------------------- | ---------------------- |
| `application/json` | JSON API data |
| `application/xml` | XML API data |
| `application/javascript` | JavaScript (preferred) |
| `application/pdf` | PDF documents |
| `application/zip` | ZIP archives |
| `application/octet-stream` | Binary files (generic) |
### Form Data
| Content-Type | Use Case |
| ----------------------------------- | --------------------- |
| `application/x-www-form-urlencoded` | HTML form submissions |
| `multipart/form-data` | File uploads |
### Images
| Content-Type | Use Case |
| --------------- | ------------ |
| `image/jpeg` | JPEG images |
| `image/png` | PNG images |
| `image/gif` | GIF images |
| `image/webp` | WebP images |
| `image/svg+xml` | SVG graphics |
### Audio/Video
| Content-Type | Use Case |
| ------------ | ---------- |
| `audio/mpeg` | MP3 audio |
| `video/mp4` | MP4 video |
| `video/webm` | WebM video |
## Request Content-Type
When sending data to a server, set Content-Type to tell the server how to parse your body.
### JSON Request
```http
POST /api/users HTTP/1.1
Host: api.example.com
Content-Type: application/json
{
"name": "Alice",
"email": "alice@example.com"
}
Form Request
POST /login HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded
username=alice&password=secret123
```text
### File Upload
```http
POST /upload HTTP/1.1
Host: example.com
Content-Type: multipart/form-data; boundary=----WebKitBoundary
------WebKitBoundary
Content-Disposition: form-data; name="file"; filename="photo.jpg"
Content-Type: image/jpeg
[binary data]
------WebKitBoundary--
Response Content-Type
Servers set Content-Type to tell clients how to handle the response.
HTML Response
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
<!DOCTYPE html>
<html>
<head><title>Page</title></head>
<body>Hello!</body>
</html>
```text
### JSON Response
```http
HTTP/1.1 200 OK
Content-Type: application/json
{"id": 123, "name": "Alice"}
File Download
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="report.pdf"
[PDF binary data]
```http
## Charset Parameter
For text content, always specify the character encoding:
```http
Content-Type: text/html; charset=utf-8
Content-Type: application/json; charset=utf-8
Content-Type: text/plain; charset=utf-8
Why Charset Matters
Without charset, browsers guess the encoding, which can cause:
- Garbled text (mojibake)
- Security vulnerabilities
- Inconsistent rendering
# ❌ Missing charset - browser guesses
Content-Type: text/html
# ✅ Explicit charset - correct rendering
Content-Type: text/html; charset=utf-8
```text
## Form Content Types
### URL-Encoded (Default)
Used by default for HTML `<form>` submissions:
```html
<form method="POST" action="/submit">
<input name="username" value="alice" />
<input name="email" value="alice@example.com" />
<button type="submit">Submit</button>
</form>
Sends:
POST /submit HTTP/1.1
Content-Type: application/x-www-form-urlencoded
username=alice&email=alice%40example.com
```text
Special characters are percent-encoded (`@` becomes `%40`).
### Multipart Form Data
Required for file uploads:
```html
<form method="POST" action="/upload" enctype="multipart/form-data">
<input type="file" name="document" />
<input name="description" value="My file" />
<button type="submit">Upload</button>
</form>
Sends:
POST /upload HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk
------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="document"; filename="report.pdf"
Content-Type: application/pdf
[PDF binary data]
------WebKitFormBoundary7MA4YWxk
Content-Disposition: form-data; name="description"
My file
------WebKitFormBoundary7MA4YWxk--
```text
## Browser Behavior
Browsers handle different content types differently:
| Content-Type | Browser Action |
| -------------------------- | --------------------------- |
| `text/html` | Render as webpage |
| `application/json` | Display raw or format |
| `image/*` | Display image |
| `application/pdf` | Open PDF viewer or download |
| `application/octet-stream` | Download file |
| `text/plain` | Display as text |
### Forcing Download
Use Content-Disposition with Content-Type:
```http
Content-Type: application/pdf
Content-Disposition: attachment; filename="report.pdf"
Security Considerations
MIME Sniffing
Browsers may ignore Content-Type and guess based on content:
# Server says plain text
Content-Type: text/plain
<script>alert('XSS')</script>
```http
Browser might execute as JavaScript! Prevent with:
```http
Content-Type: text/plain
X-Content-Type-Options: nosniff
File Upload Validation
Never trust client-provided Content-Type for uploads:
// ❌ Trusting client Content-Type
if (req.file.mimetype === 'image/jpeg') {
// Attacker can lie!
}
// ✅ Validate actual file content
const fileType = await detectFileType(req.file.buffer)
if (fileType.mime === 'image/jpeg') {
// Verified by examining file bytes
}
```javascript
## JavaScript Examples
### Fetch with JSON
```javascript
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Alice',
email: 'alice@example.com'
})
})
Fetch with Form Data
const formData = new FormData()
formData.append('username', 'alice')
formData.append('file', fileInput.files[0])
// Don't set Content-Type - browser sets it with boundary
const response = await fetch('/upload', {
method: 'POST',
body: formData
})
```javascript
### Reading Response Content-Type
```javascript
const response = await fetch('/api/data')
const contentType = response.headers.get('Content-Type')
if (contentType.includes('application/json')) {
const data = await response.json()
} else if (contentType.includes('text/')) {
const text = await response.text()
} else {
const blob = await response.blob()
}
Common Mistakes
Missing Content-Type in Requests
// ❌ Server doesn't know body format
fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ name: 'Alice' })
})
// ✅ Server knows to parse as JSON
fetch('/api/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: 'Alice' })
})
```text
### Wrong Content-Type for Response
```http
# ❌ JSON with wrong Content-Type
Content-Type: text/plain
{"name": "Alice"}
# ✅ Correct Content-Type
Content-Type: application/json
{"name": "Alice"}
Setting Content-Type for FormData
// ❌ Don't set Content-Type manually for FormData
headers: { 'Content-Type': 'multipart/form-data' }
// ✅ Let browser set it (includes boundary)
// Just don't set Content-Type header
```text
## Server Configuration
### Express.js
```javascript
// JSON responses
app.get('/api/data', (req, res) => {
res.json({ message: 'Hello' }) // Sets Content-Type automatically
})
// Custom Content-Type
app.get('/data.csv', (req, res) => {
res.setHeader('Content-Type', 'text/csv')
res.send('name,email\nAlice,alice@example.com')
})
Nginx
# Default MIME types
include /etc/nginx/mime.types;
# Custom type
types {
application/json json;
text/csv csv;
}
# Force Content-Type
location /api/ {
default_type application/json;
}
Try It Yourself
Experiment with Content-Type in our request builder:
- Select POST method
- Add a JSON body
- Observe the
Content-Type: application/jsonheader - Check the response Content-Type
Related Headers
- Accept - Client’s preferred response types
- Content-Length - Body size
- Content-Encoding - Compression
- Content-Disposition - Download behavior
- X-Content-Type-Options - Prevent MIME sniffing
Related Concepts
- HTTP Methods - Sending data
- Form Submission - HTML forms
- File Uploads - Multipart requests
In Practice
Express.js
// JSON API — res.json() sets Content-Type automatically
app.get('/api/users', (req, res) => {
res.json({ users: [] })
// Sets: Content-Type: application/json; charset=utf-8
})
// HTML response
app.get('/page', (req, res) => {
res.type('html').send('<h1>Hello</h1>')
// Sets: Content-Type: text/html; charset=utf-8
})
// File download
app.get('/report', (req, res) => {
res.set('Content-Type', 'application/pdf')
res.set('Content-Disposition', 'attachment; filename="report.pdf"')
res.send(pdfBuffer)
})Next.js App Router
// JSON — Response.json() sets Content-Type automatically
export async function GET() {
return Response.json({ users: [] })
// Sets: Content-Type: application/json
}
// Custom content type
export async function GET() {
return new Response('<feed></feed>', {
headers: { 'Content-Type': 'application/atom+xml; charset=utf-8' }
})
}Django
from django.http import JsonResponse, HttpResponse
# JSON — JsonResponse sets Content-Type automatically
def api_view(request):
return JsonResponse({'users': []})
# Sets: Content-Type: application/json
# Custom content type
def feed_view(request):
xml = '<feed></feed>'
return HttpResponse(xml, content_type='application/atom+xml; charset=utf-8')
# File download
def download_view(request):
response = HttpResponse(pdf_bytes, content_type='application/pdf')
response['Content-Disposition'] = 'attachment; filename="report.pdf"'
return responseFrequently Asked Questions
What is the Content-Type header?
Content-Type is an HTTP header that specifies the media type (MIME type) of the request or response body. It tells the recipient how to interpret and process the data, such as whether it is HTML, JSON, an image, or a file download.
What Content-Type should I use for JSON APIs?
Use application/json for JSON data. Always include charset for text types: application/json; charset=utf-8. This ensures proper encoding and helps clients parse the response correctly.
What is the difference between application/x-www-form-urlencoded and multipart/form-data?
application/x-www-form-urlencoded is the default for HTML forms and encodes data as key=value pairs. multipart/form-data is required for file uploads and sends each field as a separate part with its own content type.
Why do I need to set Content-Type in requests?
The server needs to know how to parse your request body. Without Content-Type, the server may reject the request or misinterpret the data. Always set Content-Type when sending data in POST, PUT, or PATCH requests.
What happens if Content-Type is wrong or missing?
The recipient may fail to parse the data, display it incorrectly, or reject the request. Browsers may try to guess (MIME sniffing), which can cause security issues. Always set the correct Content-Type.
Should I include charset in Content-Type?
Yes, for text-based content types. Use charset=utf-8 for HTML, JSON, XML, and plain text. Binary types like images do not need charset. Example: text/html; charset=utf-8