Enviar datos a internet
Cómo utilizar el paquete http para enviar datos a través de Internet.
Enviar datos a internet es necesario para la mayoría de las aplicaciones.
El paquete http también tiene eso cubierto.
Esta receta utiliza los siguientes pasos:
- Agrega el paquete
http. - Envía datos a un servidor utilizando el paquete
http. - Convierte la respuesta en un objeto Dart personalizado.
- Obtén un
títulode la entrada del usuario. - Mostrar la respuesta en pantalla.
1. Agregar el paquete http
#
Para agregar el paquete http como dependencia,
ejecuta flutter pub add:
flutter pub add http
Importa el paquete http.
import 'package:http/http.dart' as http;
Si estás haciendo el despliegue en Android, edita tu archivo AndroidManifest.xml para
agregar el permiso de Internet.
<!-- Required to fetch data from the internet. -->
<uses-permission android:name="android.permission.INTERNET" />
Del mismo modo, si estás haciendo el despliegue en macOS, edita tus
archivos macos/Runner/DebugProfile.entitlements y macos/Runner/Release.entitlements
para incluir el entitlement del cliente de red.
<!-- Required to fetch data from the internet. -->
<key>com.apple.security.network.client</key>
<true/>
2. Enviar datos al servidor
#Esta receta cubre cómo crear un Album
enviando el título de un álbum a
JSONPlaceholder utilizando el
método http.post().
Importa dart:convert para acceder a jsonEncode para codificar los datos:
import 'dart:convert';
Utiliza el método http.post() para enviar los datos codificados:
Future<http.Response> createAlbum(String title) {
return http.post(
Uri.parse('https://jsonplaceholder.typicode.com/albums'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{'title': title}),
);
}
El método http.post() devuelve un Future que contiene una Response.
Futurees una clase principal de Dart para trabajar con operaciones asíncronas. Un objeto Future representa un valor potencial o un error que estará disponible en algún momento en el futuro.- La clase
http.Responsecontiene los datos recibidos de una llamada http exitosa. - El método
createAlbum()toma un argumentotitleque se envía al servidor para crear unAlbum.
3. Convertir http.Response en un objeto Dart personalizado
#
Aunque es fácil realizar una solicitud de red,
trabajar con un Future<http.Response> crudo
no es muy conveniente. Para facilitarte la vida,
convierte la http.Response en un objeto de Dart.
Crear una clase Album
#Primero, crea una clase Album que contenga
los datos de la solicitud de red.
Incluye un constructor factory que
crea un Album a partir de JSON.
Convertir JSON utilizando pattern matching es solo una opción. Para obtener más información, consulta el artículo completo sobre JSON y serialización.
class Album {
final int id;
final String title;
const Album({required this.id, required this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return switch (json) {
{'id': int id, 'title': String title} => Album(id: id, title: title),
_ => throw const FormatException('Failed to load album.'),
};
}
}
Convertir la http.Response en un Album
#
Utiliza los siguientes pasos para actualizar la función createAlbum()
para que devuelva un Future<Album>:
- Convierte el cuerpo de la respuesta en un JSON
Mapcon el paquetedart:convert. - Si el servidor devuelve una respuesta
CREATEDcon un código de estado de 201, entonces convierte el JSONMapen unAlbumutilizando el método factoryfromJson(). - Si el servidor no devuelve una respuesta
CREATEDcon un código de estado de 201, entonces lanza una excepción. (Incluso en el caso de una respuesta del servidor "404 Not Found", lanza una excepción. No devuelvasnull. Esto es importante al examinar los datos ensnapshot, como se muestra a continuación).
Future<Album> createAlbum(String title) async {
final response = await http.post(
Uri.parse('https://jsonplaceholder.typicode.com/albums'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{'title': title}),
);
if (response.statusCode == 201) {
// If the server did return a 201 CREATED response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
// If the server did not return a 201 CREATED response,
// then throw an exception.
throw Exception('Failed to create album.');
}
}
¡Genial! Ahora tienes una función que envía el título a un servidor para crear un álbum.
4. Obtener un título de la entrada del usuario
#A continuación, crea un TextField para ingresar un título y
un ElevatedButton para enviar los datos al servidor.
También define un TextEditingController para leer la
entrada del usuario desde un TextField.
Cuando se presiona el ElevatedButton, el _futureAlbum
se establece con el valor devuelto por el método createAlbum().
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: _controller,
decoration: const InputDecoration(hintText: 'Enter Title'),
),
ElevatedButton(
onPressed: () {
setState(() {
_futureAlbum = createAlbum(_controller.text);
});
},
child: const Text('Create Data'),
),
],
)
Al presionar el botón Crear datos, realiza la solicitud de red,
que envía los datos en el TextField al servidor
como una solicitud POST.
El Future, _futureAlbum, se utilizará en el siguiente paso.
5. Mostrar la respuesta en pantalla
#Para mostrar los datos en pantalla, utiliza el
widget FutureBuilder.
El widget FutureBuilder viene con Flutter y
facilita el trabajo con fuentes de datos asíncronas.
Debes proporcionar dos parámetros:
- El
Futurecon el que quieres trabajar. En este caso, el future devuelto por la funcióncreateAlbum(). - Una función
builderque le indica a Flutter qué renderizar, según el estado delFuture: cargando, éxito o error.
Ten en cuenta que snapshot.hasData solo devuelve true cuando
el snapshot contiene un valor de datos no nulo.
Es por eso que la función createAlbum() debe lanzar una excepción
incluso en el caso de una respuesta del servidor "404 Not Found".
Si createAlbum() devuelve null, entonces el
CircularProgressIndicator se mostrará indefinidamente.
FutureBuilder<Album>(
future: _futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
)
Ejemplo completo
#import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Album> createAlbum(String title) async {
final response = await http.post(
Uri.parse('https://jsonplaceholder.typicode.com/albums'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{'title': title}),
);
if (response.statusCode == 201) {
// If the server did return a 201 CREATED response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
} else {
// If the server did not return a 201 CREATED response,
// then throw an exception.
throw Exception('Failed to create album.');
}
}
class Album {
final int id;
final String title;
const Album({required this.id, required this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return switch (json) {
{'id': int id, 'title': String title} => Album(id: id, title: title),
_ => throw const FormatException('Failed to load album.'),
};
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() {
return _MyAppState();
}
}
class _MyAppState extends State<MyApp> {
final TextEditingController _controller = TextEditingController();
Future<Album>? _futureAlbum;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Create Data Example',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
),
home: Scaffold(
appBar: AppBar(title: const Text('Create Data Example')),
body: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(8),
child: (_futureAlbum == null) ? buildColumn() : buildFutureBuilder(),
),
),
);
}
Column buildColumn() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: _controller,
decoration: const InputDecoration(hintText: 'Enter Title'),
),
ElevatedButton(
onPressed: () {
setState(() {
_futureAlbum = createAlbum(_controller.text);
});
},
child: const Text('Create Data'),
),
],
);
}
FutureBuilder<Album> buildFutureBuilder() {
return FutureBuilder<Album>(
future: _futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
},
);
}
}
A menos que se indique lo contrario, la documentación de este sitio refleja Flutter 3.44.0. Página actualizada por última vez el 2026-05-05. Ver código fuente oreportar un problema.