Cos'e HTTP 415 Unsupported Media Type
Il codice HTTP 415 Unsupported Media Type indica che il server rifiuta di processare la richiesta perché il Content-Type indicato dal client non e supportato da quell'endpoint, o non corrisponde al formato effettivamente atteso. E un'errore comune nelle API REST quando il client invia dati nel formato sbagliato.
Cause tipiche
- Client invia
application/xmla un'endpoint che accetta soloapplication/json. - Header
Content-Typemancante o malformato. - Charset incompatibile (es.
application/json; charset=latin-1su API UTF-8 only). - Upload di file con MIME type non in whitelist (es. .exe quando si accettano solo immagini).
- Encoding del body non supportato (es.
Content-Encoding: brsu server senza brotli).
Esempio classico
POST /api/users HTTP/1.1
Content-Type: application/xml
<user><name>Mario</name></user>
HTTP/1.1 415 Unsupported Media Type
Content-Type: application/json
Accept: application/json
{
"error": "Only application/json is accepted on this endpoint",
"supported_types": ["application/json"]
}
Header Accept del server
Il server dovrebbe (per cortesia) indicare nella risposta i tipi accettati con l'header Accept:
HTTP/1.1 415 Unsupported Media Type
Accept: application/json, application/xml
Questo permette al client di adattarsi dinamicamente senza leggere documentazione.
415 vs 406 Not Acceptable
- 415: il server non accetta il Content-Type della richiesta (cosa il client INVIA).
- 406: il server non puo produrre alcuno dei tipi richiesti nell'Accept (cosa il client VUOLE RICEVERE).
Implementazione in framework REST
Express.js:
app.use(express.json()); // accetta solo application/json
app.post('/api/users', (req, res) => {
if (!req.is('application/json')) {
return res.status(415).json({ error: 'JSON required' });
}
// ...
});
Laravel:
public function store(Request $request) {
if (!$request->isJson()) {
return response()->json(['error' => 'JSON required'], 415);
}
}
Spring:
@PostMapping(value = "/users", consumes = "application/json")
public ResponseEntity<User> createUser(@RequestBody User user) {
// Spring restituisce 415 automaticamente se Content-Type != application/json
}
Upload di file: white list MIME
Quando ricevi upload, validare il MIME type e fondamentale per sicurezza:
$allowed_mime = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (!in_array($_FILES['file']['type'], $allowed_mime)) {
http_response_code(415);
exit('Solo immagini JPEG, PNG, GIF, WebP sono accettate');
}
Attenzione: il MIME inviato dal client e modificabile. Validalo anche server-side leggendo i magic bytes del file con finfo in PHP o file command in shell.
Content-Type vs Accept
I due header hanno ruoli simmetrici:
- Content-Type: descrive il body INVIATO dal mittente.
- Accept: descrive cosa il mittente accetta nella risposta.
Errori 415 derivano da Content-Type incompatibili; errori 406 da Accept incompatibili.
Charset e parametri
Il Content-Type puo includere parametri:
Content-Type: application/json; charset=utf-8
Content-Type: text/csv; charset=iso-8859-1; header=present
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Server stricti possono restituire 415 se il charset non corrisponde a quello atteso, anche se il tipo base e corretto.
Debug pratico
curl -X POST -H "Content-Type: application/json" \
-d '{"key": "value"}' \
-i https://api.example.com/endpoint
Se ricevi 415, controlla:
- Il valore esatto di Content-Type (case sensitive in alcuni server).
- Presenza di charset corretto.
- Sintassi corretta del body (un JSON malformato puo essere segnalato come 415 anziche 400).
- Documentazione API per i tipi attesi.
Content negotiation
API moderne possono accettare più formati e adattarsi:
@PostMapping(value = "/users", consumes = {"application/json", "application/xml"})
Così la stessa endpoint accetta JSON o XML, scegliendo il parser in base a Content-Type.
Vary header
Se il tuo endpoint risponde diversamente in base a Content-Type, includi Vary: Content-Type per dire ai cache che la risposta dipende da quell'header.
Magic bytes validation
Il client puo dichiarare qualsiasi MIME type nell'header Content-Type, ma server attento valida via magic bytes (primi byte del file che identificano il formato). Esempio PHP: $mime = mime_content_type($tmp_path);. Esempio Python: magic.from_file(path, mime=True). Se MIME dichiarato != MIME reale, emetti 415 e logga il tentativo.
Charset utf-8 obbligatorio
API moderne dovrebbero richiedere application/json; charset=utf-8 e rifiutare altri charset con 415. UTF-8 e standard de facto, evita problemi di encoding misto e bug di serializzazione. Documentare nelle API docs.
Versioning via media type
Alcune API usano content negotiation per versioning: application/vnd.gtg.api.v2+json. Client invia Accept: vnd.gtg.api.v2+json, server risponde con quel content-type. Versioni non supportate: 406 (per Accept) o 415 (per Content-Type request).
Multipart edge cases
Form HTML con file usano multipart/form-data con boundary. Server che riceve application/x-www-form-urlencoded al posto di multipart deve emettere 415, perché non puo parsare file dal form encoding URL.
Differenze tra framework
Express richiede middleware (express.json, express.urlencoded). Senza, ogni POST con body diventa 400 o 415 a seconda. Laravel parsa automaticamente in base a Content-Type. FastAPI con Pydantic e molto strict: tipo MIME deve corrispondere al decoder Pydantic.
Esempi avanzati di MIME validation
Per file con polyfill MIME (es. SVG che puo contenere JS, ZIP-based formats come .docx/.xlsx), validation deve essere strict:
$tmp = $_FILES['file']['tmp_name'];
$mime = mime_content_type($tmp);
$ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
$valid = [
'image/jpeg' => ['jpg', 'jpeg'],
'image/png' => ['png'],
];
if (!isset($valid[$mime]) || !in_array($ext, $valid[$mime])) {
http_response_code(415);
exit;
}
Content sniffing in browser
Browser fanno "MIME sniffing": se MIME e generico (text/plain) ma il contenuto sembra HTML, lo trattano come HTML. Pericoloso per XSS. Mitigazione: header X-Content-Type-Options: nosniff nelle risposte.
415 in webhook receivers
Webhook providers spesso inviano JSON. Se il tuo receiver supporta solo XML, 415 e corretto. Documenta nei meta della tua API webhook quali content-type accetti, e fornisci esempi chiari.
Hai bisogno di aiuto?
Se il tuo sito mostra errori HTTP, il team di G Tech Group puo aiutarti. Contattaci tramite il modulo di contatto.