HttpRequest în Dart

HTTP (dart:io) Dart 1.0

HttpRequest este o cerere primită de HttpServer: metoda (GET, POST), adresa (uri), antetele, corpul și răspunsul de trimis.

Sintaxă
abstract interface class HttpRequest implements Stream<Uint8List> {
  String get method;
  Uri get uri;
  HttpHeaders get headers;
  HttpResponse get response;
}

Ce face HttpRequest

Fiecare cerere primită de HttpServer este un obiect HttpRequest. method este metoda HTTP cu litere mari ("GET", "POST", "DELETE"…). uri este adresa cerută, fără server: uri.path dă calea (/elevi), iar uri.queryParameters parametrii de după ?, deja decodificați.

Cererea este și un flux de octeți: corpul trimis de client (de exemplu JSON la un POST) îl citești cu await utf8.decoder.bind(cerere).join(). Antetele sunt în cerere.headers.

cerere.response este un HttpResponse (un IOSink): setezi întâi statusCode și antetele (headers.contentType), apoi scrii corpul cu write și termini cu await response.close(). Fiecare cerere trebuie să primească exact un răspuns închis.

Exemple

Exemplul 1: Metoda și adresa cererii

Serverul afișează ce primește, apoi clientul afișează răspunsul.

import 'dart:convert';
import 'dart:io';

Future<void> main() async {
  final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
  server.listen((cerere) {
    print('[server] ${cerere.method} ${cerere.uri.path} ${cerere.uri.queryParameters}');
    cerere.response
      ..write('OK')
      ..close();
  });

  final client = HttpClient();
  final uri = Uri.http('127.0.0.1:${server.port}', '/cauta', {'oras': 'Târgu Mureș', 'pagina': '2'});
  final raspuns = await (await client.getUrl(uri)).close();
  print('[client] ${raspuns.statusCode} ${await raspuns.transform(utf8.decoder).join()}');
  client.close();
  await server.close();
}

Rezultat

[server] GET /cauta {oras: Târgu Mureș, pagina: 2}
[client] 200 OK

Exemplul 2: Răspuns JSON cu status și antete

import 'dart:convert';
import 'dart:io';

Future<void> main() async {
  final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
  server.listen((cerere) async {
    final raspuns = cerere.response;
    if (cerere.method != 'GET') {
      raspuns.statusCode = HttpStatus.methodNotAllowed;
    } else {
      raspuns.headers.contentType = ContentType.json;
      raspuns.write(jsonEncode({'oras': 'Iași', 'temperatura': 18}));
    }
    await raspuns.close();
  });

  final client = HttpClient();
  final adresa = Uri.parse('http://127.0.0.1:${server.port}/vreme');
  final r1 = await (await client.getUrl(adresa)).close();
  print('GET: ${r1.statusCode} ${r1.headers.contentType} ${await r1.transform(utf8.decoder).join()}');
  final r2 = await (await client.deleteUrl(adresa)).close();
  await r2.drain<void>();
  print('DELETE: ${r2.statusCode} ${r2.reasonPhrase}');
  client.close();
  await server.close();
}

Rezultat

GET: 200 application/json; charset=utf-8 {"oras":"Iași","temperatura":18}
DELETE: 405 Method Not Allowed

Exemplul 3: Citirea corpului unei cereri POST

import 'dart:convert';
import 'dart:io';

Future<void> main() async {
  final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
  server.listen((cerere) async {
    final text = await utf8.decoder.bind(cerere).join();
    final elev = jsonDecode(text) as Map<String, dynamic>;
    print('[server] am primit ${cerere.headers.contentType?.mimeType}: $elev');
    cerere.response
      ..statusCode = HttpStatus.created
      ..write('Elevul ${elev['nume']} a fost înscris în clasa ${elev['clasa']}.');
    await cerere.response.close();
  });

  final client = HttpClient();
  final cerere = await client.postUrl(Uri.parse('http://127.0.0.1:${server.port}/elevi'));
  cerere.headers.contentType = ContentType.json;
  cerere.write(jsonEncode({'nume': 'Maria', 'clasa': '9B'}));
  final raspuns = await cerere.close();
  print('[client] ${raspuns.statusCode}: ${await raspuns.transform(utf8.decoder).join()}');
  client.close();
  await server.close();
}

Rezultat

[server] am primit application/json: {nume: Maria, clasa: 9B}
[client] 201: Elevul Maria a fost înscris în clasa 9B.

Greșeli frecvente

  • Setezi statusCode sau antetele după write: antetele au plecat deja și se aruncă StateError. Setează-le întâi.
  • Compari cerere.method cu 'get': metoda vine cu litere mari, 'GET'.
  • Citești cerere.uri.query și îl împarți manual: uri.queryParameters face asta corect, inclusiv decodificarea lui %C8%99 în „ș”.

Comenzi înrudite

  • HttpServer: HttpServer.bind pornește un server web pe o adresă și un port; serverul este un flux de cereri (HttpRequest).
  • HttpClient.getUrl: getUrl deschide o cerere GET (citire), postUrl o cerere POST (trimitere de date) spre adresa dată.
  • HttpClient: HttpClient trimite cereri HTTP și HTTPS din programele Dart de consolă și server; close îl închide la final.
  • jsonEncode: Transformă hărți, liste, texte, numere, bool și null într-un text JSON; alte obiecte trebuie să aibă toJson().
  • IOSink: Destinația în care scrii text sau octeți: un fișier deschis (openWrite), stdout, stderr sau răspunsul HTTP.