티스토리 뷰
Flutter 애플리케이션에서 데이터를 서버로 전송하는 기능은 사용자 입력을 처리하거나 백엔드와 상호작용하기 위해 필수적입니다. 특히 사용자 등록, 로그인, 데이터 제출 등의 기능에서 HTTP 요청을 통해 데이터를 전송하는 작업이 많이 사용됩니다. 이번 글에서는 Flutter에서 데이터를 서버로 전송하는 방법을 단계별로 알아보고, 주요 팁과 함께 쉽게 이해할 수 있도록 설명합니다.
왜 Flutter에서 데이터 전송이 중요한가?
Flutter 앱에서 데이터를 서버로 전송해야 하는 주요 이유는 다음과 같습니다:
- 사용자 입력 처리: 사용자로부터 입력된 데이터를 서버로 보내 저장하거나 처리.
- 백엔드와 상호작용: REST API를 호출하여 서버와 데이터를 주고받음.
- 실시간 데이터 반영: 데이터베이스에 정보를 추가하거나 수정하여 앱에서 실시간으로 반영.
Flutter에서 데이터 전송의 기본 구현
1. http
패키지 설치
Flutter에서 HTTP 요청을 처리하기 위해 http
패키지를 사용합니다. pubspec.yaml
파일에 다음을 추가합니다:
dependencies:
http: ^0.15.0
그리고 터미널에서 다음 명령어를 실행하세요:
flutter pub get
2. 기본적인 POST 요청 구현
HTTP POST 요청은 데이터를 서버로 전송하는 데 가장 일반적으로 사용됩니다. 아래는 간단한 POST 요청 예제입니다.
import 'package:http/http.dart' as http;
Future<void> sendData() async {
final url = Uri.parse('https://example.com/api/data');
final response = await http.post(
url,
headers: {'Content-Type': 'application/json'},
body: '{"name": "Flutter", "message": "Hello World"}',
);
if (response.statusCode == 200) {
print('Data sent successfully: ${response.body}');
} else {
print('Failed to send data: ${response.statusCode}');
}
}
데이터를 서버로 전송하는 주요 단계
1. JSON 데이터 준비
Flutter에서는 JSON 포맷으로 데이터를 서버로 전송하는 경우가 많습니다. Dart의 내장 dart:convert
패키지를 사용하여 JSON 데이터를 쉽게 생성할 수 있습니다.
import 'dart:convert';
Map<String, String> data = {
'name': 'Flutter',
'message': 'Hello World',
};
String jsonData = jsonEncode(data);
2. 헤더 추가
HTTP 요청에 필요한 헤더를 추가하여 서버와 통신합니다. 대부분의 경우 Content-Type
헤더를 설정합니다.
headers: {'Content-Type': 'application/json'},
3. 비동기 처리
HTTP 요청은 네트워크 지연이 발생할 수 있으므로 비동기 방식으로 처리해야 합니다. async
와 await
를 사용하여 네트워크 요청을 효율적으로 처리합니다.
POST 요청 예제: 사용자 데이터 전송
사용자 정보를 서버로 전송하는 예제를 살펴보겠습니다.
Future<void> sendUserData(String name, String email) async {
final url = Uri.parse('https://example.com/api/users');
final response = await http.post(
url,
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'name': name, 'email': email}),
);
if (response.statusCode == 201) {
print('User data sent successfully: ${response.body}');
} else {
print('Failed to send user data: ${response.statusCode}');
}
}
에러 처리 및 디버깅
1. 에러 핸들링
HTTP 요청이 실패할 경우 적절한 에러 핸들링이 필요합니다.
try {
final response = await http.post(url, body: jsonData);
if (response.statusCode != 200) {
throw Exception('Failed to send data');
}
} catch (e) {
print('Error: $e');
}
2. 디버깅
네트워크 요청 및 응답 데이터를 로깅하여 디버깅 정보를 제공합니다.
print('Request: $jsonData');
print('Response: ${response.body}');
상태 관리와 데이터 전송
Flutter 앱이 복잡해질수록 상태 관리 라이브러리를 사용해 데이터를 처리하는 것이 효율적입니다.
- Provider: 앱 전반에서 상태를 공유하며 네트워크 요청과 데이터를 관리.
- Riverpod: 상태 관리와 비동기 데이터 처리를 쉽게 구현.
요약: Flutter에서 데이터 전송의 핵심
- HTTP 패키지를 사용해 간단한 POST 요청 구현.
- JSON 데이터를 생성하고 헤더를 설정.
- 에러 처리와 디버깅으로 요청 신뢰성 강화.
- 상태 관리 라이브러리를 활용하여 데이터 흐름 최적화.
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();
},
);
}
}
'Flutter Cookbook' 카테고리의 다른 글
Flutter로 HTTP DELETE 요청 보내기: 데이터 삭제의 기본 원리와 구현 방법 (1) | 2024.12.05 |
---|---|
Flutter에서 HTTP를 활용한 데이터 업데이트: 단계별 가이드 (3) | 2024.12.04 |
Flutter에서 인증된 요청 처리하기: 단계별 가이드 (0) | 2024.12.02 |
Flutter로 인터넷에서 데이터 가져오기: 완벽 가이드 (2) | 2024.12.01 |
Flutter에서 데이터를 전달하는 방법: 간단하고 명확한 가이드 (0) | 2024.11.30 |