[Flutter] 스나이퍼팩토리 Flutter 기초과정 (15)

GONG·2023년 4월 11일
0
post-thumbnail

15일차 과제 링크 👉 15일차 과제

HTTP

  • HTML 문서와 같은 리소스들을 가져올 수 있도록 해주는 프로토콜
  • 프론트엔드에서는 서버에 요청을 보내서 응답을 받고, 그 응답 데이터를 가공하여 보여줘야 함

HTTP Method

→ 서버가 수행해야 할 동작을 지정하여 요청을 보내는 방법

  • 주요 메소드
    메소드설명
    GET리소스 조회, 주로 데이터를 받을 때 사용
    POST요청 데이터 처리, 주로 데이터 생성할 때 사용
    PUT리소스를 대체 (덮어쓰기), 해당 리소스가 없으면 생성
    PATCH리소스 부분 변경 (PUT이 전체 변경, PATCH는 일부 변경)
    DELETE리소스 삭제

Dart에서 HTTP 요청해보기

  1. http 패키지 설치

    • https://pub.dev/packages/http
    • http 요청을 보내고 응답을 받을 수 있는 다트 공식 패키지
    • pubspec.yaml > dependencies에 http: ^0.13.5 등록
  2. HTTP 사용할 대상의 URL 정의

  3. Method 선택 (GET, POST)

  4. 요청 보내기

  5. 요청 응답받기

  6. 출력

    var url = 'https://sniperfactory.com/sfac/http_test';
    var response = await http.get(Uri.parse(url)); // string 형태의 url을 Uri로 바꿈
    
    print(response.statusCode);  // 200 : 요청 성공
    print(response.body);        // {"result":"스나이퍼팩토리 비밀 URL에 접근하시다니."}

[URI와 URL의 차이]


URI

  • "Uniform Resource Identifier"의 약자로, 인터넷에서 식별 가능한 리소스를 나타내는 일반적인 용어
  • 식별자와 리소스의 위치를 모두 나타낼 수 있음

URL

  • "Uniform Resource Locator"의 약자로, 인터넷에서 리소스의 위치를 나타내는 것
  • 일반적으로 웹 브라우저에서 입력하는 것과 같이, 프로토콜, 호스트명, 리소스 경로 등을 포함하는 문자열
  • 일반적으로 인터넷에서 식별 가능한 리소스를 나타내는 데 사용됨

차이

  • URI는 리소스의 위치뿐만 아니라 식별자도 포함할 수 있지만, URL은 리소스의 위치만 포함한다.
  • 예를 들어, URI는 ISBN 번호와 같은 고유한 식별자를 사용하여 책을 나타낼 수 있지만, URL은 해당 책이 있는 위치를 식별함

서버에서는 요청을 받을 때 컨트롤이 가능

  • User-Agent로 어떤 브라우저에서 요청을 보냈는지 확인이 가능하다.
  • 무슨 메소드의 요청을 보냈는지에 따라 응답을 다르게 줄 수 있다.

Get만 사용되는 경우

  • 데이터를 읽거나(read) 검색(retreive)할 때 사용되는 메서드
  • 주로 데이터를 읽을 때 사용됨
    void main() async {
    	var url = 'https://sniperfactory.com/sfac/http_only_get';
    	
    	var getResponse = await http.get(Uri.parse(url));
    	print(getResponse.body);      // {"result":"정답입니다! GET 요청만 받는 경우도 정말정말 많습니다."}
    	
    	var postResponse = await http.post(Uri.parse(url));
    	print(postResponse.body);  // {"error":"GET 요청만 받습니다."}
    }

Post만 사용되는 경우

  • 데이터를 새로 생성(create)할 때 사용되는 메서드
  • 주로 데이터를 생성할 때 사용됨
    void main() async {
      var url = 'https://sniperfactory.com/sfac/http_only_post';
      
      var postResponse = await http.post(Uri.parse(url));
      print(postResponse.body);      // {"result":"정답입니다! POST 요청만 받는 경우도 정말정말 많습니다."}
      
      var getResponse = await http.get(Uri.parse(url));
      print(getResponse.body);  // {"error":"POST 요청만 받습니다."}
    }

Dio

  • https://pub.dev/packages/dio
  • 기존 http 패키지보다 더 많은 기능을 담고 있다
  • 요청 대상에 대한 설정, 연결 정보를 미리 설정해 줄 수 있다
  • 파일(이미지), 다중파일같은 FormData를 사용해야할 때 손쉽게 구현가능

Dio를 통해 HTTP 요청하기

  • 기본 설정값 세팅 가능
    var dio = Dio();
    
    dio.options.baseUrl = url;    // baseUrl: 가장 기본이 되는 RouteURL (도메인 최상위 URL)

GET

  • dio.get()
    var dio = Dio();
    var getRes = await dio.get('https://sniperfactory.com/sfac/http_only_get');
    // var postRes = await dio.post('https://sniperfactory.com/sfac/http_only_get');
    
    print(getRes);   // {"result":"정답입니다! POST 요청만 받는 경우도 정말정말 많습니다."}
    // print(postRes);  // 400: Bad Request

POST

  • dio.post()
    var dio = Dio();
    var postRes = await dio.post('https://sniperfactory.com/sfac/http_only_post');
    // var getRes = await dio.get('https://sniperfactory.com/sfac/http_only_post');
    
    print(postRes); // {"result":"정답입니다! POST 요청만 받는 경우도 정말정말 많습니다."}
    // print(getRes);  // 400: Bad Request

HTTP Header: user-agent

  • 사용자가 접속한 브라우저가 무엇인지 알고 싶을 때
    var dio = Dio();
    
    var res = await dio.get(
      'https://sniperfactory.com/sfac/http_only_chrome_browser',
      options: Options(
        headers: {
          'user-agent': 'Chrome'
          // 'user-agent': 'Safari'  // 400: Bad Request
        }
      )
    );
    print(res);   // {"result":"정답입니다! 이런 꿀잼 과제라니"}

HTTP Header: JWT token

  • 중요한 데이터는 인증된 사용자만 접근할 수 있도록 기밀성을 보장해야 함
  • 기밀성을 보장하기 위해서 등장한 것이 토큰 방식
  • 로그인 → 로그인 성공 → 서버가 JWT 토큰 발급 → 디바이스에 저장 → 요청시 JWT 토큰 장착
    var dio = Dio();
    var res = await dio.get(
      'https://sniperfactory.com/sfac/http_only_jwt_included',
      options: Options(
        headers: {
          // 인증키를 첨부할 수 있는 key 값
          'authorization': 'asdfasdf'
        }
      )
    );
    print(res);   // {"result":"정답입니다! 이런 꿀잼 과제라니"}

HTTP vs DIO

  • 차이점
    import 'package:dio/dio.dart';
    import 'package:http/http.dart' as http;
    
    var dio = Dio();
    var url = 'https://sniperfactory.com/sfac/http_json_data';
    
    void main() {
      getDataUsingDio();
      getDataUsingHttp();
    }
    
    void getDataUsingHttp() async {
      var res = await http.get(Uri.parse(url));
      print('Http : $res');   // Instance of 'Future<Response>'
      print('Http res.body : ${res.body}');   // {"item":{"name":"스나이퍼팩토리 플러터 과정","description":"스나이퍼팩토리의 플러터 과정입니다! 지금 바로 신청해볼까요?","image":"https://picsum.photos/200/200","price":4000000}}
      print('Http res.body.runtimeType : ${res.body.runtimeType}');   // String
    }
    
    void getDataUsingDio() async {
      var res = await dio.get(url);
      print('Dio : $res');    // {"item":{"name":"스나이퍼팩토리 플러터 과정","description":"스나이퍼팩토리의 플러터 과정입니다! 지금 바로 신청해볼까요?","image":"https://picsum.photos/200/200","price":4000000}}
      print('Dio res.data : ${res.data}');    // {item: {name: 스나이퍼팩토리 플러터 과정, description: 스나이퍼팩토리의 플러터 과정입니다! 지금 바로 신청해볼까요?, image: https://picsum.photos/200/200, price: 4000000}}
      print('Dio res.data.runtimeType : ${res.data.runtimeType}');  // _InternalLinkedHashMap<String, dynamic>
    	print('Dio res.data item : ${res.data['item']['name']}');
    }
    • http는 String, dio는 InternalLinkedHashMap<String, dynamic> 타입으로 데이터를 가져온다.

[추가 비교]


HTTP

  • GET, POST, PUT, DELETE 등 HTTP 메서드를 지원
  • 헤더 및 쿼리 매개변수를 설정할 수 있음
  • 인증 정보를 설정할 수 있음
  • 쿠키를 사용할 수 있음
  • 인터셉터를 사용하여 요청과 응답을 수정할 수 있음
  • 타임아웃 및 소켓 연결 설정을 지원
  • 플러터 앱과 통합된 예외 처리를 제공

Dio

  • FormData 및 멀티파트 요청을 지원
  • JSON 직렬화 및 역직렬화를 지원
  • Interceptor를 사용하여 HTTP 요청과 응답을 수정하고 로깅할 수 있음
  • 쿠키 지원
  • 자동 취소 기능 제공
  • 다운로드 및 업로드 기능을 제공
  • 자체 캐시 시스템 지원
  • http 패키지는 간단한 HTTP 요청을 처리하기에 적합
  • Dio 패키지는 좀 더 복잡한 HTTP 요청 및 응답 처리를 위해 사용됨



비동기

동기(Synchronous)

작업을 순차적으로 실행하며, 한 작업이 완료될 때까지 다음 작업을 수행할 수 없음

[동기의 장점과 단점]

장점


  • 코드가 간단하며, 순차적으로 실행됨
  • 에러가 발생했을 때 디버깅하기 쉽다
  • 결과가 도착할 때까지 대기하므로 동기적인 방식은 동시성 제어 문제를 해결할 수 있다

단점


  • 대기 시간이 발생하면 블로킹(blocking)이 발생하여 시스템 전체의 처리 속도가 느려짐
  • 대규모 사용자가 있는 시스템에서는 처리 속도가 매우 느려질 수 있음
  • 서버 측의 자원을 많이 차지할 수 있다

비동기(Asynchronous)

한 작업이 끝날 때까지 기다리지 않고 다른 작업을 수행할 수 있는 방식

[비동기의 장점과 단점]

장점


  • 비동기적 방식이 대부분의 경우 더 빠름
  • 작업이 완료되는 동안 대기할 필요가 없으므로 다른 작업을 수행할 수 있음
  • 다수의 작업이 동시에 수행될 수 있다

단점


  • 비동기적인 방식은 설계가 복잡함
  • 에러 처리가 어려울 수 있음
  • 결과가 순서대로 도착하지 않을 수 있으므로 일부 알고리즘에서는 사용할 수 없다

[예시]


I/O 작업을 수행할 때 파일을 읽거나 네트워크를 통해 데이터를 받아오는 등의 작업은 시간이 오래 걸리기 때문에 동기적으로 수행하면 애플리케이션이 블로킹되어 다른 작업을 수행할 수 없음.

비동기적으로 수행하면 I/O 작업이 수행되는 동안 다른 작업을 수행할 수 있으므로 애플리케이션의 성능을 향상시킬 수 있다

Future 데이터 타입

  • 비동기 작업의 결과를 나타내는 객체
  • 작업이 완료될 때 결과값을 가지고 완료됨. 결과값이 없는 작업의 경우 void를 반환

async

  • async 함수는 비동기 작업을 수행

await

  • await 키워드는 Future객체가 완료될 때까지 함수의 실행을 일시 중지
    void main() async {
      print('로그인을 시도합니다.');
      await Future.delayed(Duration(seconds: 3));
      print('로그인에 성공했습니다');
      print('반갑소');
    }
    로그인을 시도합니다.
    (3초 뒤)
    로그인에 성공했습니다
    반갑소

then

  • Future객체에 대해 비동기 작업이 완료되면, then()메서드를 사용하여 결과를 처리할 수 있음
  • 일단 실행시켜놓고 끝나면 별도로 처리하는 작업을 만들겠다
  • 다음 실행 대상의 코드와 연관은 없지만 최소한 처리 표시는 하고싶은 경
    void main() async {
    	print('로그인을 시도합니다.');
    	Future.delayed(Duration(seconds: 3)).then((res) {
    	  print(res);
    	  print('로그인에 성공했습니다');
    	});
    	print('반갑소');
    }
    로그인을 시도합니다.
    반갑소
    (3초 뒤)
    null
    로그인에 성공했습니다
  • 플러터에서 버튼을 누르면 네트워크에서 이미지를 가져오고 난 뒤 응답을 확인하여 화면에 갱신하는 코드
    • 데이터를 담을 변수를 만든다
      var message = '';
    • 데이터를 보여줄 위젯을 만든다.
      Text(message);
    • 네트워크에 Future 코드를 작성해서 데이터를 기다렸다가 받아오는 함수를 만든다.
      Future<String> getData() async {
      	var dio = Dio();
      	var res = await dio.get('https://sniperfactory.com/sfac/http_test');
      	return res.data['result'];
      }
    • 이벤트 핸들러 (함수)를 만든다
      void handleOnPressed() async {
      	message = await getData();
      }
    • TextButton을 만들어서 이벤트가 발생되면 함수를 실행시킨다.
      TextButton(
      	onPressed: () {
      		handleOnPressed();
      	}
      	child: Text('데이터 가져오기'),
      )

15일차 끝

차가운 챗선생......

profile
우와재밋다

0개의 댓글