1. Library
  2. Http and the Web
  3. Headers

Updated 10 hours ago

Every HTTP response carries a question the browser needs answered before it can do anything useful: "What am I looking at?"

The Content-Type header provides that answer. Without it, the same bytes that render as a photograph become meaningless garbage—or worse, executable code the browser didn't expect to run.

What Content-Type Actually Does

Content-Type specifies the media type (also called MIME type) of the data being transmitted. It appears in both requests and responses:

In responses, it tells the browser how to interpret what it received:

Content-Type: text/html; charset=utf-8

In requests, it tells the server how to parse what you're sending:

Content-Type: application/json

Get this wrong and things break silently. Send JSON with the wrong Content-Type and your server won't parse it. Serve an image with text/html and watch the browser try to render binary data as a webpage.

MIME Type Structure

MIME stands for "Multipurpose Internet Mail Extensions"—originally designed for email, adopted by HTTP. The format is simple:

type/subtype

The type is the broad category. The subtype is the specific format:

  • text/html — Text category, HTML format
  • image/png — Image category, PNG format
  • application/json — Application category, JSON format

Some MIME types include parameters:

text/html; charset=utf-8
multipart/form-data; boundary=----WebKitFormBoundary

Common MIME Types

Text

MIME TypeUse
text/htmlHTML webpages
text/plainPlain text without markup
text/cssCSS stylesheets
text/javascriptJavaScript code

Application

MIME TypeUse
application/jsonJSON data (the standard for modern APIs)
application/xmlXML data
application/pdfPDF documents
application/zipZIP archives
application/octet-streamGeneric binary (when specific type is unknown)
application/x-www-form-urlencodedForm data encoded as URL parameters

Images

MIME TypeUse
image/pngPNG images
image/jpegJPEG images
image/gifGIF images
image/svg+xmlSVG vector graphics
image/webpWebP (modern, efficient format)

Video and Audio

MIME TypeUse
video/mp4MP4 videos
video/webmWebM videos
audio/mpegMP3 audio
audio/wavWAV audio

Multipart

multipart/form-data is special—it allows mixing different content types in a single request, essential for forms that include both text fields and file uploads:

Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

Character Encoding

For text content, the charset parameter specifies how characters are encoded:

Content-Type: text/html; charset=utf-8

Always use UTF-8. It supports every character from every language, it's backward compatible with ASCII, and it's the universal standard. Other encodings like ISO-8859-1 or Shift_JIS exist for legacy compatibility, but unless you're maintaining ancient systems, UTF-8 is the answer.

Omitting the charset forces browsers to guess, and guessing leads to garbled text—the infamous "mojibake" where international characters become question marks or random symbols.

Content Negotiation

Clients can request specific formats using the Accept header:

Accept: application/json, application/xml;q=0.9, */*;q=0.8

The q parameter indicates preference (0 to 1). Here, JSON is most preferred (implicit q=1.0), XML is acceptable (q=0.9), and anything else is a last resort (q=0.8).

The server examines this and responds with the best match. This lets a single API endpoint serve JSON to web apps and XML to legacy systems, based on what each client asks for.

Why Getting This Wrong Is Dangerous

Security Vulnerabilities

Mislabeled content can turn your browser into an unwitting accomplice:

  1. Attacker uploads an HTML file containing malicious JavaScript
  2. Server stores it, perhaps as "profile-picture.jpg"
  3. Server serves it with Content-Type: text/html
  4. Browser obediently executes the JavaScript—XSS attack complete

The X-Content-Type-Options: nosniff header prevents browsers from second-guessing the Content-Type. With this header, the browser trusts your declaration absolutely—so you'd better get it right.

Silent API Failures

This is one of the most common debugging headaches:

// This silently fails—server receives garbage
fetch('/api/users', {
    method: 'POST',
    headers: {
        'Content-Type': 'text/plain'  // Wrong!
    },
    body: JSON.stringify({ name: 'Alice' })
});

// This works—Content-Type matches the data
fetch('/api/users', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({ name: 'Alice' })
});

The server sees the Content-Type, decides how to parse the body, and if they don't match, your data arrives as nonsense.

Broken Downloads and Displays

Browsers decide what to do based entirely on Content-Type:

  • text/html → Parse and render as a webpage
  • application/json → Display raw text (or offer download)
  • image/png → Render inline as an image
  • application/pdf → Open PDF viewer
  • application/octet-stream → Prompt to download

Serve a PDF with text/html and watch the browser try to render binary data as a webpage—a screen full of gibberish.

File Extensions Don't Matter (to HTTP)

File extensions like .jpg, .pdf, or .html are conventions for operating systems. HTTP doesn't care. The Content-Type header is the only truth.

A file named vacation.jpg served with Content-Type: application/pdf will open as a PDF. A file named malware.exe served with Content-Type: image/png will display as a (broken) image.

This creates a rule worth following: make extensions match Content-Type. Not because HTTP requires it, but because humans maintaining the system will thank you.

Custom MIME Types

Applications can define custom types, typically with the application/vnd. prefix (vendor-specific):

Content-Type: application/vnd.github.v3+json

This GitHub API example encodes the vendor (GitHub), version (v3), and underlying format (JSON) all in one type. Useful for API versioning and proprietary formats.

Debugging Content-Type Issues

Browser DevTools make this visible:

  1. Open DevTools (F12)
  2. Go to the Network tab
  3. Click any request
  4. Check the Headers section

You'll see both the request's Content-Type (what you claimed to send) and the response's Content-Type (what the server claims it returned). When things break mysteriously, this is often where the answer hides.

Frequently Asked Questions About Content-Type and MIME Types

Was this page helpful?

😔
🤨
😃
Content-Type and MIME Types • Library • Connected