Kodokon kodokon.com

Eine HTTP-API aufrufen: Dekodierung und Bildschirmzustände

Baue einen professionellen Netzwerkaufruf mit dem Paket http auf: Timeout, Statuscodes, typisierte Dekodierung und vollständige Zustände.

11 Min. · 3 Fragen

Diese Lektion in Kodokon öffnen

Das Paket http deckt das Wesentliche ab: Anfragen, Header, Body. dio ergänzt Interceptors, Abbruch und Wiederholversuche, auf Kosten einer schwereren Abhängigkeit - eine gute Wahl, sobald die App über ein paar Endpunkte hinauswächst. Egal welcher Client: Der Aufbau eines seriösen Netzwerkaufrufs bleibt derselbe - ein Timeout, eine Prüfung des HTTP-Statuscodes, eine typisierte Dekodierung und drei Bildschirmzustände (Laden, Fehler, Daten), die ausdrücklich behandelt werden.

BASH
flutter pub add http
DART
import 'dart:convert';

import 'package:http/http.dart' as http;

class Article {
  const Article({required this.title});

  factory Article.fromJson(Map<String, dynamic> json) =>
      Article(title: json['title'] as String);

  final String title;
}

Future<List<Article>> fetchArticles() async {
  final uri = Uri.https('api.example.com', '/articles');
  final response = await http
      .get(uri)
      .timeout(const Duration(seconds: 8));
  if (response.statusCode != 200) {
    throw Exception('HTTP ${response.statusCode}');
  }
  final body = utf8.decode(response.bodyBytes);
  final data = jsonDecode(body) as List<dynamic>;
  return [
    for (final item in data)
      Article.fromJson(item as Map<String, dynamic>),
  ];
}
Timeout, geprüfter Status, UTF-8-Dekodierung und dann Typisierung.

Zwei Verhaltensweisen überraschen viele. Erstens: http wirft bei einem Status 404 oder 500 keine Ausnahme - aus Sicht des Netzwerks ist die Anfrage "gelungen", also musst du statusCode selbst prüfen. Zweitens: jsonDecode liefert dynamic; caste sofort (as List<dynamic>, as Map<String, dynamic>), um die Typisierung wiederherzustellen. Bei großen Datenmengen lagerst du die Dekodierung mit compute in ein Isolate aus, damit die UI nicht einfriert.

Bleibt noch, den Zustand des Bildschirms abzubilden. Boolesche Flags wie isLoading in Kombination mit error != null landen immer in widersprüchlichen Zuständen (Laden und Fehler gleichzeitig). Eine sealed-Klasse macht die Zustände wechselseitig ausschließend und das switch vollständig: Wenn du morgen einen Zustand ergänzt, zeigt dir der Compiler jeden Bildschirm, den du anpassen musst.

DART
import 'package:flutter/material.dart';

sealed class ArticlesState {
  const ArticlesState();
}

class ArticlesLoading extends ArticlesState {
  const ArticlesLoading();
}

class ArticlesError extends ArticlesState {
  const ArticlesError(this.message);

  final String message;
}

class ArticlesLoaded extends ArticlesState {
  const ArticlesLoaded(this.titles);

  final List<String> titles;
}

Widget buildArticlesBody(ArticlesState state) {
  return switch (state) {
    ArticlesLoading() => const Center(
        child: CircularProgressIndicator(),
      ),
    ArticlesError(:final message) => Center(
        child: Text(message),
      ),
    ArticlesLoaded(:final titles) => ListView.builder(
        itemCount: titles.length,
        itemBuilder: (context, index) => ListTile(
          title: Text(titles[index]),
        ),
      ),
  };
}
Ein vollständiges switch: Kein Zustand kann vergessen werden.

Wissenscheck

Stelle sicher, dass du die wichtigsten Punkte dieser Lektion behalten hast.

  1. Dein http.get-Aufruf erhält eine 500-Antwort. Was macht das Paket http?
    • Es wirft eine Ausnahme, die du mit try/catch abfangen kannst.
    • Es liefert die Response ganz normal zurück: Du musst statusCode selbst prüfen.
    • Es wiederholt die Anfrage automatisch dreimal.
  2. Umlaute und Sonderzeichen werden in den empfangenen Daten falsch angezeigt. Die wahrscheinlichste Ursache?
    • jsonDecode beherrscht UTF-8 nicht.
    • Flutter kann Sonderzeichen ohne ein spezielles Paket nicht anzeigen.
    • Der Server lässt das Charset weg: response.body wird dann als latin-1 dekodiert; verwende utf8.decode(response.bodyBytes).
  3. Was ist der entscheidende Vorteil einer sealed-Klasse, um den Zustand eines Bildschirms zu modellieren?
    • Das switch wird vollständig: Der Compiler meldet jeden nicht behandelten Zustand.
    • Der Bildschirm wird dadurch schneller gerendert.
    • Man kann damit den Zustand ändern, ohne das Widget neu zu bauen.