Skip to main content
{/}codefunc
Web & APIAugust 8, 2026 · 5 min read

Content-Type and MIME Types: Headers, Uploads, and API Responses

Get Content-Type right for APIs, file uploads, and static assets — charset parameters, multipart boundaries, sniffing risks, and a practical MIME lookup workflow.

By codefunc

mime-typescontent-typehttpuploadsapidata-uri

Every HTTP response that carries a body should say what that body is. The Content-Type header is how clients decide to parse JSON, render HTML, download a PDF, or reject a file upload. When the header is missing, wrong, or disagrees with the bytes, browsers guess — and guessing is how XSS slips through "safe" downloads and how mobile apps throw opaque parse errors on perfectly valid payloads.

Bottom line: Set Content-Type deliberately on API responses and uploads; include charset for text; never trust a client-supplied type without verifying magic bytes. Look up extensions and types with MIME Type Lookup, inspect raw header blocks with HTTP Header Parser, and decode data: URLs with Data URI Parser — all client-side.

Who this guide is for

Frontend and API developers who debug fetch failures, configure static hosting, accept file uploads, or wire multipart forms. If you have ever fixed a bug by "adding application/json" and hoped for the best, this guide makes the rules explicit.

MIME type basics

A MIME type (media type) looks like:

type/subtype[; parameter=value]

Examples:

Content-Type: application/json
Content-Type: text/html; charset=utf-8
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxk
Content-Type: image/png
Type tree Role
text/* Textual; often needs charset
application/* Opaque or structured data (json, pdf, octet-stream)
image/*, audio/*, video/* Binary media
multipart/* Several parts, each with headers
font/* Web fonts

IANA registers official types; browsers also recognize common unofficial ones. When inventing a private format, prefer application/vnd.yourcompany.thing+json over overloading text/plain.

Content-Type on API responses

JSON APIs should send:

Content-Type: application/json; charset=utf-8

Notes:

  • charset on JSON is optional in theory (JSON is Unicode) but harmless and clarifies legacy clients.
  • text/json is wrong — use application/json.
  • text/plain with a JSON body forces clients to opt into parsing; some fetch wrappers will not auto-.json().
  • Error bodies should keep a consistent type. Returning HTML error pages with 200 + text/html to an API client is a frequent gateway bug.

For fetch:

const res = await fetch("/api/items");
const type = res.headers.get("content-type") ?? "";
if (!type.includes("application/json")) {
  throw new Error(`Expected JSON, got ${type}`);
}

Paste a captured response header block into HTTP Header Parser when you need to see duplicates, casing, or proxy-injected fields clearly.

Request Content-Type: what you send

Body Header
JSON application/json
URL-encoded form application/x-www-form-urlencoded
Multipart upload multipart/form-data; boundary=… (set by the runtime)
Raw file PUT Match the file (image/png, …)
GraphQL over HTTP Usually application/json

With FormData in the browser, do not set Content-Type manually — the boundary parameter must match the body, and fetch / XMLHttpRequest will set it for you. Overriding with multipart/form-data and no boundary breaks servers.

File uploads and server validation

Never trust File.type or the client Content-Type alone. Browsers guess from extension; attackers rename files.

Defense in depth:

  1. Allowlist extensions and server-side MIME detection from magic bytes
  2. Store files outside the web root or serve with Content-Disposition: attachment when appropriate
  3. Force safe Content-Type when serving user content (for example, always image/jpeg after re-encoding)
  4. Reject text/html and image/svg+xml uploads if you will serve them inline without sanitization — SVG can carry script

Use MIME Type Lookup during development to map .wasmapplication/wasm, .woff2font/woff2, .csvtext/csv, and similarly for less common assets. Wrong static-host mappings cause browsers to refuse fonts (CORS + type) or fail module loads.

Charset and text pitfalls

For text/html, text/css, text/plain, and similar:

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

Missing charset leads to legacy encoding guesswork (mojibake). Serving UTF-8 bytes labeled as ISO-8859-1 corrupts non-ASCII. Keep files, DB connections, and HTTP headers aligned on UTF-8.

CSV downloads deserve care: Excel often expects a BOM or a vendor-specific type. Prefer text/csv; charset=utf-8 and document open-in-Excel quirks separately.

Static hosting cheat sheet

Extension Typical Content-Type
.html text/html; charset=utf-8
.js / .mjs text/javascript; charset=utf-8
.css text/css; charset=utf-8
.json application/json
.svg image/svg+xml
.wasm application/wasm
.map application/json
unknown application/octet-stream (download)

Service workers and module scripts are strict about types. A JS file served as application/octet-stream may not execute as a module.

Content sniffing and security

Browsers historically sniffed bytes when Content-Type was missing or generic. Mitigations:

X-Content-Type-Options: nosniff

Pair nosniff with accurate types. Serving untrusted HTML as text/plain without nosniff has led to past XSS vectors in some browsers. For user-generated files, prefer attachment disposition plus correct types plus sanitization.

data: URLs and embedded types

Data URLs embed a MIME type in the URI:

data:image/png;base64,iVBORw0KGgo…
data:text/plain;charset=utf-8,hello

When you receive an opaque data: string, parse it before trusting the payload. Data URI Parser splits media type, parameters, and data so you can verify you are about to embed an image — not text/html with a script — into the DOM.

Debugging checklist

Symptom Likely Content-Type issue
res.json() throws Body is HTML error page or empty
Font blocked Wrong type or missing CORS on font file
CSV opens as garbage Charset / BOM / wrong type
Upload rejected Boundary missing; client overrode header
Browser renders download as page text/html on attacker-controlled bytes
SW fails to cache JS Script served with wrong MIME

Capture headers from DevTools, paste into HTTP Header Parser, and confirm the type against MIME Type Lookup.

Use these codefunc tools alongside this guide:

Practical takeaway

Treat Content-Type as part of your API contract, not decoration. Send precise types for JSON and static assets, let the browser set multipart boundaries, validate uploads by content rather than client labels, and disable sniffing with X-Content-Type-Options: nosniff. When debugging, look up the expected type, parse the header block, and inspect embedded data: media types locally with MIME Type Lookup, HTTP Header Parser, and Data URI Parser — no data needs to leave your machine.

Sources

Try it on codefunc

Related articles

3

Search tools

Find a developer tool