본문 바로가기

MOBILE/ios

[iOS] URLSession을 사용하여 POST method 통신하기

HTTP의 기본 구조

HTTP는 요청을 일정한 형식의 텍스트 기반 메세지로 변환한 메세지 형식을 말한다. 크게 요청, 응답으로 구분된다.

 

메세지는 모두 다음과 같은 구조이다.

Line - Header - Body

 

Line은 메세지의 가장 기본적인 내용이 담긴다. 예를 들어, 응답 or 요청인지 구분 여부, 메세지 전송 방식, 상태 정보 등이다.

Header 는 메세지 본문에 대한 메타 정보가 담긴다.

Body는 실제 보내고자 하는 메세지 내용이 담긴다.

이러한 메세지의 형식은 정형화 되어있다. 즉 형태가 고정되어 있다는 의미이다.

 

라인 영역은 반드시 한줄이어야 하며, 그 아래에는 여러줄의 헤더가 작성된다.

헤더와 바디 영역은 구분되어야 하기 때문에 한 줄의 공백이 들어간다.

말하자면 다음과 같은 구조이다.

 

 

GET 방식은 Body를 사용하지 않기 때문에 Content-Type 헤더가 필요없다.

또한 보내고자 하는 데이터도 파라미터를 URL 뒤에 쿼리 스트링으로 연결해서 전송한다.

하지만 URL 경로는 1024 Byte만 허용하므로 긴 정보는 보내기 어렵다.

 


HTTPS

HTTP는 메세지를 모두 텍스트 기반으로 보낸다. 따라서 이 패킷을 누가 중간에 가로채서 확인해볼 수 도 있다. 이러한 공격을 sniffing(스니핑)이라고 한다.

이러한 보안 상의 문제를 막기 위해 인증서를 통해 패킷을 암호화 한 다음에 전송하는 방식이 바로 HTTPS이다. HTTP + Security이다.

보안인증에는 SSL 인증, TLS 등 다양한 버전이 존재한다.

 

REST, Representational State Transfer

HTTP를 위한 아키텍쳐의 한 형식이다. 즉 HTTP 기반 메세지를 쉽게 주고받기 위한 인터페이스이다.


POST 방식으로 통신하기

 

크게 다음 4가지 과정으로 진행된다.

 

1. 데이터 준비 (URLEncoding 적용 필요)

2. URL 객체 정의

3. URLReqeust 객체 정의 및 HTTP 헤더 설정

4. URLSession 객체로 API 호출

 

// 1. 데이터 준비
let param = "userID=josushell&name=josueyeon"
let paramData = param.data(using: .utf8)

// 2. URL 객체
let url = URL(string: USERAPI)

// 3. URLRequest 객체 및 HTTP 설정
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.httpBody = param

request.addvalue("application/x-www-form-urlencoded", fotHTTPHeaderField: "Content-Type")
request.addvalue(String(paramData!.count), forHTTPHeaderField: "Content-Length")

// 4. URLSession API 호출
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in }

task.resume()

 

1. 데이터 준비

데이터는 공백, 한글, 특수 문자 등의 변형 가능성이 존재하는 문자를 완전하게 전송하기 위해서 URL encoding을 진행해야 한다.

swift에서는 Data 객체 형식으로 변형하면 자동으로 인코딩을 해준다.

 

2. URL 객체 정의

 

이 객체에는 API 호출 URL 객체를 직접 입력하는 경우가 많다.

 

3. URLReqeust 객체 정의 및 HTTP 헤더 설정

 

URLRequest 객체는 실제로 API를 호출할 때 필요한 정보들이 모두 포함한다. 즉 HTTP 요청 메세지 구조를 구성한다.

메세지 전송 방식(GET/POST) 은 .httpMethod 속성에 설정한다.

메세지 본문은 .httpBody 속성에 설정한다.

 

request components 설정 가능 속성은 다음과 같다.

 

 

 

header는 실제 메세지는 아니지만 메세지에 대한 정보를 포함하는 메타 정보이다. 그렇다면 header의 정보는 어떻게 설정할까?

다음의 메소드를 사용한다.

 

 

header 에 Content-Type 은 메세지 본문이 어떤 형식으로 작성되어 있는지 나타낸다.

이때 들어가는 application/x-www-form-urlencoded 는 POST 방식으로 데이터를 전송하는 것을 의미한다.

메세지 본문의 형식은 이 헤더의 타입과 일치해야 한다.

 

이 x-www-form-urlencoded 타입은 특수문자의 경우 URLEncoding 형식으로 변환한다.

URLEncoding이란 URL 문자에서 사용되는 특수문자 (예를 들면 데이터를 연결하는 &) 가 전송하는 값 내에도 있을 때 이를 겹치지 않는 다른 특수문자 형식으로 변환하여 데이터를 오류없이 전송하는 것이다.

 

Content-Length는 전송할 메세지 본문의 길이를 알려준다.

Data 객체는 count 속성을 사용 가능하다.

 

 

4. URLSession 객체로 API 호출

URLSession 객체는 singleton 패턴이므로 shared 속성을 통해 참조 가능하다.

 

dataTask(with:) 메소드의 파라미터로 urlrequest 객체를 전달하면 전송 가능하다.

HTTP 통신은 비동기로 이루어지기 때문에 이러한 응답값에 대한 처리도 클로저로 작성해서 알아서 호출하도록 해야한다.

 

응답 클로저는 세가지의 매개변수가 있다.

- 응답 메세지 본문: Data 타입

- 응답 코드 및 메타 정보가 포함된 응답 정보: URLResponse 타입

- 오류 정보: Error 타입

 

dataTask(with:) 메소드는 전송 준비를 끝내고 대기하는 함수이다.

따라서 전송하기 위해서는 HTTP 메세지를 전송하는 메소드인 resume() 을 사용해야 한다.

 

이 객체에 대해 더 자세하게 알아보자


URLSession

 

 

URLSession 객체는 다음과 같은 라이프 사이클을 가진다.

- Session

- Request

- Task

 

Session

URLSession의 종류는 크게 3가지이다.

 

1. default session

기본적인 session이다. 디스크 기반의 caching을 지원한다.

 

2. Ephemeral session

데이터를 저장하지 않는다. 즉 cache, cookie, disk 입력을 하지 않는다.

 

3. Background session

app이 실행중이 아닐때에도 download, upload 등의 동작을 백그라운드에서 진행 한다.

 

Reqeust

URLRequest 객체로 요청 메세지 구조를 구성하여 전달한다.

 

Task

Task 객체는 session 객체가 보낸 메세지에 대한 응답을 돌려받는 역할을 한다.

 

 

Task 객체 또한 크게 3가지로 구분된다.

 

1. Data Task

NSData 객체를 사용하여 데이터를 주고받는다.

짧고 interactive 한 요청에 대해서 주로 사용된다.

 

2. Upload Task

data task와 비슷하지만 background 에서도 동작 가능하다는 차이가 있다.

 

3. Download Task

file 형태로 데이터를 받고 background 동작을 지원한다.

 

중요한 점은 URLSession은 비동기로 수행되기 때문에 서브 스레드에서 실행된다는 것이다. 따라서 UI 에 접근하는 로직이 있다면 이를 메인 스레드에서 진행할 수 있도록 DispatchQueue.main.async() 를 사용해야한다.