서버와의 데이터 통신은 웹 애플리케이션에서 매우 중요한 역할을 한다. Dart에서는 HTTP 패키지를 활용하여 쉽게 서버와 통신할 수 있다. 이 챕터에서는 Dart의 HTTP 패키지를 사용하여 서버에 요청을 보내고, 데이터를 주고받는 방법을 설명한다. 다양한 HTTP 요청 방식과 서버 응답 처리 방법에 대해 다룬다.

HTTP 요청 방식

서버와의 통신을 위해 HTTP 요청 방식을 이해하는 것이 중요하다. HTTP 요청은 클라이언트가 서버에 데이터를 요청하거나 전달하는 방식이다. Dart에서 HTTP 요청을 수행할 때 사용할 수 있는 주요 방식은 다음과 같다:

GET 요청

GET 요청은 서버로부터 데이터를 요청하는 가장 기본적인 방식이다. 클라이언트가 서버에 요청을 보내면 서버는 해당 요청에 대한 데이터를 응답으로 돌려준다. Dart에서는 http.get 메소드를 사용하여 GET 요청을 보낼 수 있다.

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

void fetchData() async {
  var response = await http.get(Uri.parse('https://example.com/data'));
  if (response.statusCode == 200) {
    print('Response data: ${response.body}');
  } else {
    print('Failed to load data');
  }
}

위 코드에서는 http.get 메소드를 사용하여 https://example.com/data 주소로 GET 요청을 보내고, 서버가 성공적으로 응답한 경우 그 데이터를 출력한다.

POST 요청

POST 요청은 클라이언트가 서버로 데이터를 전송할 때 사용된다. 이를 통해 새로운 데이터를 서버에 저장하거나 처리할 수 있다. Dart에서 POST 요청을 보내려면 http.post 메소드를 사용한다.

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

void sendData() async {
  var response = await http.post(
    Uri.parse('https://example.com/data'),
    body: {'key1': 'value1', 'key2': 'value2'},
  );
  if (response.statusCode == 200) {
    print('Data sent successfully');
  } else {
    print('Failed to send data');
  }
}

이 예제에서는 POST 요청을 통해 서버로 데이터를 전송하고, 성공적으로 전송된 경우 "Data sent successfully"라는 메시지를 출력한다.

비동기 처리

HTTP 요청은 네트워크 통신이기 때문에 응답 시간이 길어질 수 있다. 이를 처리하기 위해 Dart에서는 비동기 프로그래밍을 활용하여 HTTP 요청이 완료될 때까지 기다리는 동안 다른 작업을 수행할 수 있도록 한다. Dart에서 비동기 처리를 위해 async, await 키워드를 사용한다.

async는 비동기 함수임을 나타내며, await는 해당 작업이 완료될 때까지 대기한다는 의미이다.

Future<void> fetchDataAsync() async {
  var response = await http.get(Uri.parse('https://example.com/data'));
  print(response.body);
}

위 코드에서 fetchDataAsync 함수는 async 키워드를 사용하여 비동기적으로 실행되며, await 키워드를 사용하여 HTTP 요청이 완료될 때까지 기다린다.

서버 응답 처리

서버가 클라이언트로 응답을 보내면, 해당 응답에는 상태 코드와 응답 본문이 포함된다. 상태 코드는 서버가 요청을 성공적으로 처리했는지 여부를 나타내며, 대표적인 상태 코드는 다음과 같다:

서버 응답 본문은 요청한 데이터를 포함하거나, 에러 메시지를 포함할 수 있다. Dart에서는 http.Response 객체를 사용하여 응답의 상태 코드와 본문을 처리할 수 있다.

void handleResponse(http.Response response) {
  if (response.statusCode == 200) {
    print('Success: ${response.body}');
  } else {
    print('Error: ${response.statusCode}');
  }
}

이 코드는 서버의 응답 상태 코드를 확인하고, 성공적인 응답과 에러를 구분하여 처리하는 방법을 보여준다.

JSON 데이터 처리

서버와 클라이언트 간의 데이터 통신에서는 주로 JSON 형식을 사용하여 데이터를 주고받는다. Dart에서 JSON 데이터를 처리하기 위해 dart:convert 패키지를 사용할 수 있다. JSON 데이터를 Dart 객체로 변환하거나, Dart 객체를 JSON 형식으로 변환할 때 사용된다.

import 'dart:convert';

void parseJson(String jsonString) {
  var data = jsonDecode(jsonString);
  print('Parsed data: $data');
}

String jsonString = jsonEncode({'key': 'value'});

이 예제에서는 jsonDecode를 사용하여 JSON 문자열을 Dart 객체로 변환하고, jsonEncode를 사용하여 Dart 객체를 JSON 문자열로 변환하는 과정을 보여준다.

PUT 요청

PUT 요청은 서버의 기존 데이터를 수정하거나 업데이트할 때 사용된다. 서버에서 기존 리소스를 업데이트하거나 새 리소스를 생성할 때 유용하게 사용된다. Dart에서는 http.put 메소드를 사용하여 PUT 요청을 보낼 수 있다.

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

void updateData() async {
  var response = await http.put(
    Uri.parse('https://example.com/data/1'),
    body: {'name': 'updated_name', 'value': 'updated_value'},
  );
  if (response.statusCode == 200) {
    print('Data updated successfully');
  } else {
    print('Failed to update data');
  }
}

위 코드에서는 PUT 요청을 통해 특정 리소스(/data/1)의 데이터를 업데이트하고, 서버 응답 상태 코드가 200일 경우 업데이트 성공 메시지를 출력한다.

DELETE 요청

DELETE 요청은 서버에서 리소스를 삭제할 때 사용된다. 클라이언트가 서버에 특정 데이터를 삭제하도록 요청하는 방식이다. Dart에서는 http.delete 메소드를 사용하여 DELETE 요청을 보낼 수 있다.

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

void deleteData() async {
  var response = await http.delete(Uri.parse('https://example.com/data/1'));
  if (response.statusCode == 200) {
    print('Data deleted successfully');
  } else {
    print('Failed to delete data');
  }
}

이 예제에서는 특정 리소스(/data/1)를 서버에서 삭제하고, 성공적인 응답을 처리하는 방법을 보여준다.

헤더 설정

서버와의 통신에서 헤더(Header)는 클라이언트가 서버에 요청할 때 함께 전송하는 추가적인 정보를 포함한다. 예를 들어, Content-Type이나 인증 정보 등을 헤더에 포함하여 서버에 요청을 보낼 수 있다.

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

void sendDataWithHeaders() async {
  var response = await http.post(
    Uri.parse('https://example.com/data'),
    headers: {'Content-Type': 'application/json'},
    body: '{"key": "value"}',
  );
  if (response.statusCode == 200) {
    print('Request sent with headers');
  } else {
    print('Failed to send request with headers');
  }
}

이 코드에서는 Content-Typeapplication/json으로 지정하여 JSON 데이터를 서버에 전송하고, 서버 응답을 처리하는 방법을 설명한다.

인증 처리

서버와 클라이언트 간의 보안 통신에서는 인증(Authorization)이 중요한 요소이다. Dart에서 서버와의 통신 시 인증 정보를 헤더에 포함하여 보낼 수 있다. 가장 일반적인 방식 중 하나는 Bearer 토큰을 사용하는 방식이다.

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

void sendAuthenticatedRequest() async {
  var response = await http.get(
    Uri.parse('https://example.com/protected'),
    headers: {'Authorization': 'Bearer your_token_here'},
  );
  if (response.statusCode == 200) {
    print('Authenticated request successful');
  } else {
    print('Failed to authenticate request');
  }
}

이 예제에서는 Authorization 헤더에 Bearer 토큰을 포함하여 서버의 보호된 리소스에 접근하는 방법을 보여준다.

Stream을 통한 데이터 처리

Dart의 Stream은 서버로부터 지속적으로 데이터를 받아야 할 때 유용하다. 예를 들어 실시간으로 데이터를 주고받는 WebSocket 통신이나 서버에서 데이터를 스트리밍 방식으로 받아야 할 때 사용된다.

Dart의 Stream은 비동기 데이터 이벤트를 처리하는 데 유용한 도구이며, HTTP 패키지에서도 Stream 기반으로 서버와의 데이터를 주고받을 수 있다.

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

void streamData() async {
  var request = http.Request('GET', Uri.parse('https://example.com/stream'));
  var response = await request.send();

  response.stream.transform(utf8.decoder).listen((value) {
    print('Received chunk: $value');
  });
}

이 코드는 Request 객체를 사용하여 서버에 스트리밍 요청을 보내고, 서버가 반환하는 데이터를 스트리밍 방식으로 받아서 처리하는 방법을 설명한다.

서버로 데이터 보내기: Form 데이터 전송

Dart에서는 서버에 데이터를 보낼 때 다양한 방식으로 데이터를 전송할 수 있다. 가장 기본적인 방법 중 하나는 Form 데이터를 사용하는 방식이다. Form 데이터는 일반적으로 키-값 쌍으로 이루어진 데이터를 서버에 전송하는 방식으로, 특히 HTML 폼에서 입력된 데이터를 전송할 때 많이 사용된다.

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

void sendFormData() async {
  var response = await http.post(
    Uri.parse('https://example.com/form'),
    body: {
      'username': 'exampleUser',
      'password': 'examplePassword',
    },
  );
  if (response.statusCode == 200) {
    print('Form data sent successfully');
  } else {
    print('Failed to send form data');
  }
}

위 코드에서는 Form 형식으로 데이터를 서버에 전송하고, 성공적으로 전송되었을 경우 statusCode200인지를 확인하는 방법을 보여준다.

서버로 파일 전송

서버와의 통신에서 파일을 전송할 때는 MultipartRequest를 사용하여 파일을 업로드할 수 있다. Dart의 HTTP 패키지에서는 http.MultipartRequest 클래스를 사용하여 여러 파트로 이루어진 요청을 서버에 보낼 수 있다.

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

void sendFile() async {
  var request = http.MultipartRequest(
    'POST',
    Uri.parse('https://example.com/upload'),
  );
  request.files.add(await http.MultipartFile.fromPath('file', 'path/to/file'));

  var response = await request.send();
  if (response.statusCode == 200) {
    print('File uploaded successfully');
  } else {
    print('Failed to upload file');
  }
}

이 코드는 MultipartRequest를 통해 서버로 파일을 전송하는 방법을 설명한다. http.MultipartFile.fromPath 메소드를 사용하여 파일 경로를 지정하고, 해당 파일을 서버로 업로드한다.

서버로 JSON 데이터 전송

Dart에서 서버와의 통신 시 가장 많이 사용하는 데이터 형식 중 하나는 JSON이다. JSON은 경량 데이터 교환 형식으로, Dart에서 서버로 JSON 데이터를 전송하려면 HTTP 요청의 Content-Typeapplication/json으로 지정하고, 데이터를 JSON 형식으로 인코딩하여 전송할 수 있다.

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

void sendJsonData() async {
  var response = await http.post(
    Uri.parse('https://example.com/json'),
    headers: {'Content-Type': 'application/json'},
    body: jsonEncode({'name': 'example', 'age': 30}),
  );
  if (response.statusCode == 200) {
    print('JSON data sent successfully');
  } else {
    print('Failed to send JSON data');
  }
}

이 예제에서는 jsonEncode 함수를 사용하여 Dart 객체를 JSON 형식으로 변환하고, 이를 서버에 전송하는 방법을 보여준다. 서버에서 응답을 받을 때도 마찬가지로 JSON 데이터를 처리할 수 있다.

서버 응답에 따른 데이터 처리

서버로부터 받은 응답은 다양한 데이터 형식일 수 있다. Dart에서는 서버 응답 데이터를 처리할 때 주로 JSON 형식을 사용하며, 이를 Dart 객체로 변환한 후 원하는 방식으로 데이터를 사용할 수 있다.

import 'dart:convert';

void handleJsonResponse(String responseBody) {
  var data = jsonDecode(responseBody);
  print('Name: ${data['name']}');
  print('Age: ${data['age']}');
}

서버에서 받은 JSON 응답을 처리할 때는 jsonDecode 함수를 사용하여 문자열을 Dart 객체로 변환하고, 객체의 각 필드를 접근하여 원하는 데이터를 사용할 수 있다.

네트워크 에러 처리

서버와의 데이터 통신에서 발생할 수 있는 다양한 에러를 처리하는 것이 중요하다. Dart에서는 HTTP 요청을 보낼 때 발생할 수 있는 네트워크 오류나 서버 오류를 처리하기 위해 try-catch 구문을 사용할 수 있다.

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

void fetchDataWithErrorHandling() async {
  try {
    var response = await http.get(Uri.parse('https://example.com/data'));
    if (response.statusCode == 200) {
      var data = jsonDecode(response.body);
      print('Data received: $data');
    } else {
      print('Server error: ${response.statusCode}');
    }
  } catch (e) {
    print('Failed to fetch data: $e');
  }
}

이 코드는 네트워크 오류 및 서버 오류를 처리하는 방법을 보여준다. try-catch 구문을 사용하여 서버가 응답하지 않거나 잘못된 응답을 보낸 경우에 대한 오류 처리를 할 수 있다.