Nicht jede erfolgreiche Antwort hat einen Körper

Bei jedem Scanstart stand in der Verwaltung "JSON.parse: unexpected end of
data" — eine Fehlermeldung für etwas, das tadellos funktioniert hatte.

Gemessen: der Scan-Endpunkt antwortet mit 202 Accepted, Content-Length 0
und ohne Content-Type. Er läuft im Hintergrund weiter, da gibt es noch
nichts zu melden. Der Abruf-Helfer behandelte aber nur 204 als leer und
liess JSON.parse auf eine leere Zeichenkette los.

Jetzt entscheidet der Inhalt, nicht der Status. Eine Liste von
Status-Codes wäre wieder eine, die beim nächsten Endpunkt unvollständig
ist.

Dazu: die Zeile "Metadaten" nannte die Sprache ein zweites Mal, obwohl sie
seit kurzem eine eigene Zeile hat.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-10-04 14:22:47 +02:00
co-authored by Claude Opus 5
parent 98565e14b5
commit b64497acd5
2 changed files with 26 additions and 3 deletions
+23 -1
View File
@@ -207,7 +207,29 @@ async function anfrage<T>(pfad: string, opts: RequestInit = {}): Promise<T> {
throw new ApiFehler(antwort.status, text); throw new ApiFehler(antwort.status, text);
} }
return antwort.status === 204 ? (undefined as T) : antwort.json(); // **Nicht jede erfolgreiche Antwort hat einen Körper.**
//
// Vorher galt das nur für 204. Der Scan antwortet aber mit 202 Accepted und
// ohne Inhalt — er läuft im Hintergrund weiter, da gibt es noch nichts zu
// melden. `JSON.parse` lief dann auf eine leere Zeichenkette, und in der
// Verwaltung stand bei jedem Scanstart „unexpected end of data": eine
// Fehlermeldung für etwas, das tadellos funktioniert hatte.
//
// Geprüft wird der Inhalt, nicht der Status. Eine Liste von Status-Codes
// wäre wieder eine, die beim nächsten Endpunkt unvollständig ist.
if (antwort.status === 204 || antwort.status === 205) return undefined as T;
const laenge = antwort.headers.get('Content-Length');
const art = antwort.headers.get('Content-Type') ?? '';
if (laenge === '0' || !art.includes('json')) {
// Ohne `Content-Length` — etwa bei Chunked-Übertragung — entscheidet der
// Text selbst.
const text = await antwort.text();
if (text.trim().length === 0) return undefined as T;
return JSON.parse(text) as T;
}
return antwort.json();
} }
/* ---------- Bilder ---------- */ /* ---------- Bilder ---------- */
+3 -2
View File
@@ -872,8 +872,9 @@ function serverbereich(geaendert: () => void): HTMLElement {
liste.appendChild(zeile( liste.appendChild(zeile(
'Metadaten', 'Metadaten',
stand.usingProjectKey ? `Mitgelieferter TMDB-Zugang · ${stand.language}` // Ohne die Sprache: die steht eine Zeile tiefer und gehört dort hin.
: stand.hasApiKey ? `Eigener TMDB-Zugang · ${stand.language}` stand.usingProjectKey ? 'Mitgelieferter TMDB-Zugang'
: stand.hasApiKey ? 'Eigener TMDB-Zugang'
: 'Kein Zugang hinterlegt', : 'Kein Zugang hinterlegt',
stand.usingProjectKey stand.usingProjectKey
? 'Ein eigener Zugang löst den mitgelieferten ab.' ? 'Ein eigener Zugang löst den mitgelieferten ab.'