http통신

2022. 5. 24. 22:38- IOS/swift

앱을 만들다 보면 서버와 통신이 없는 프로젝트는 거의 없을 정도로 서버통신은 중요한 부분입니다.

웹서버 통신은 크게 2가지 종류로 나눌수 있습니다.

  • HTTP 통신 : URL 기반으로 클라이언트에서 요청을 보내고, 서버로부터 응답을 받는 형태의 통신
  • 웹소켓 통신 : 클라이언트와 서버가 특정 port를 통해 연결되어있는 양방향 형태의 통신. 실시간 통신에 주로 사용

오늘은 IOS 앱에서의 HTTP / HTTPS 통신하는법을 살펴볼 예정입니다.

 

URLSession

URLSession은 HTTP / HTTPS기반의 URL로부터 데이터를 다운로드하거나 업로드 하는 API를 제공하는 클래스 입니다.

 

URLSession은 자체적으로 비동기적으로 작동하게 구현되어 있으므로, 따로 비동기 처리할 필요가 없습니다.

대신 completionHandler를 작성할 때, UI관련작업을 수행한다면 반드시 Main 스레드에서 작업해주어야 합니다.

 

 

URLSessionConfiguration

URLSession은 configuration이라는 객체를 가지고 있습니다.

업로드할지 다운로드 할지 등의 행동과 규칙을 정의 하는 객체입니다.

 

URLSession 객체를 초기화 하기 전에 가장 먼저 작업해야할 첫 단계이며

타임아웃 값, 캐싱 정책, HTTP헤더와 같은 값들로 구성됩니다.

 

URLSession 종류

URLSession의 종류는 configuraion 객체에 의해 결정된다.

 

  • 공유 세션 (싱글톤) : URLSession.shared()
    1. 기본요청을 위한 세션
    2. configuration 객체 없음
    3. 사용자 정의 불가

  • 기본 세션 : URLSession(configuration: .default)
    1. 디스크에 기록함 (캐시, 쿠키, 자격증명)
    2. delegate 지정 가능 (순차적으로 데이터 처리)
  • 임시 세션 : URLSession(configuration: .ephemeral)
    1. 디스크에 데이터를 쓰지 않음 (캐시, 쿠키, 인증 등)
    2. 메모리에 올려서 세션을 연결하고, 세션 만료 시 데이터 사라짐 -> 비공개 세션이라고 생각하면 됨
  • 백그라운드 세션 : URLSession(configuration: .background)
    1. 백그라운드에서 업로드, 다운로드가 가능함
    2. 별도의 프로세스가 모든 데이터 전송을 처리 (앱이 중지되거나 종료되어도 계속함)

 

 

[ 소스 코드 예제 ]

 

func requestGet() {
        // [URL 지정 및 파라미터 값 지정 실시]
        var urlComponents = URLComponents(string: "https://jsonplaceholder.typicode.com/posts?")
        let paramQuery_1 = URLQueryItem(name: "userId", value: "1")
        let paramQuery_2 = URLQueryItem(name: "id", value: "1")
        urlComponents?.queryItems?.append(paramQuery_1) // 파라미터 지정
        urlComponents?.queryItems?.append(paramQuery_2) // 파라미터 지정
        
        
        // [http 통신 타입 및 헤더 지정 실시]
        var requestURL = URLRequest(url: (urlComponents?.url)!)
        requestURL.httpMethod = "GET" // GET
        requestURL.addValue("application/x-www-form-urlencoded; charset=utf-8;", forHTTPHeaderField: "Content-Type") // GET

        
        // [http 요쳥을 위한 URLSessionDataTask 생성]
        print("")
        print("====================================")
        print("[requestGet : http get 요청 실시]")
        print("url : ", requestURL)
        print("====================================")
        print("")
        let dataTask = URLSession.shared.dataTask(with: requestURL) { (data, response, error) in

            // [error가 존재하면 종료]
            guard error == nil else {
                print("")
                print("====================================")
                print("[requestGet : http get 요청 실패]")
                print("fail : ", error?.localizedDescription ?? "")
                print("====================================")
                print("")
                return
            }

            // [status 코드 체크 실시]
            let successsRange = 200..<300
            guard let statusCode = (response as? HTTPURLResponse)?.statusCode, successsRange.contains(statusCode)
            else {
                print("")
                print("====================================")
                print("[requestGet : http get 요청 에러]")
                print("error : ", (response as? HTTPURLResponse)?.statusCode ?? 0)
                print("msg : ", (response as? HTTPURLResponse)?.description ?? "")
                print("====================================")
                print("")
                return
            }

            // [response 데이터 획득, utf8인코딩을 통해 string형태로 변환]
            let resultCode = (response as? HTTPURLResponse)?.statusCode ?? 0
            let resultLen = data! // 데이터 길이
            let resultString = String(data: resultLen, encoding: .utf8) ?? "" // 응답 메시지
            print("")
            print("====================================")
            print("[requestGet : http get 요청 성공]")
            print("resultCode : ", resultCode)
            print("resultLen : ", resultLen)
            print("resultString : ", resultString)
            print("====================================")
            print("")
        }

        // network 통신 실행
        dataTask.resume()
    }
​

​

​

    func requestPOST() {
        // [URL 지정 및 파라미터 값 지정 실시]
        var urlComponents = URLComponents(string: "https://jsonplaceholder.typicode.com/posts?")
        let paramQuery_1 = URLQueryItem(name: "userId", value: "1")
        let paramQuery_2 = URLQueryItem(name: "id", value: "1")
        urlComponents?.queryItems?.append(paramQuery_1) // 파라미터 지정
        urlComponents?.queryItems?.append(paramQuery_2) // 파라미터 지정
        
        
        // [http 통신 타입 및 헤더 지정 실시]
        var requestURL = URLRequest(url: (urlComponents?.url)!)
        requestURL.httpMethod = "POST" // POST
        requestURL.addValue("application/json", forHTTPHeaderField: "Content-Type") // POST

        
        // [http 요쳥을 위한 URLSessionDataTask 생성]
        print("")
        print("====================================")
        print("[requestPOST : http post 요청 실시]")
        print("url : ", requestURL)
        print("====================================")
        print("")
        let dataTask = URLSession.shared.dataTask(with: requestURL) { (data, response, error) in

            // [error가 존재하면 종료]
            guard error == nil else {
                print("")
                print("====================================")
                print("[requestPOST : http post 요청 실패]")
                print("fail : ", error?.localizedDescription ?? "")
                print("====================================")
                print("")
                return
            }

            // [status 코드 체크 실시]
            let successsRange = 200..<300
            guard let statusCode = (response as? HTTPURLResponse)?.statusCode, successsRange.contains(statusCode)
            else {
                print("")
                print("====================================")
                print("[requestPOST : http post 요청 에러]")
                print("error : ", (response as? HTTPURLResponse)?.statusCode ?? 0)
                print("msg : ", (response as? HTTPURLResponse)?.description ?? "")
                print("====================================")
                print("")
                return
            }

            // [response 데이터 획득, utf8인코딩을 통해 string형태로 변환]
            let resultCode = (response as? HTTPURLResponse)?.statusCode ?? 0
            let resultLen = data! // 데이터 길이
            let resultString = String(data: resultLen, encoding: .utf8) ?? "" // 응답 메시지
            print("")
            print("====================================")
            print("[requestPOST : http post 요청 성공]")
            print("resultCode : ", resultCode)
            print("resultLen : ", resultLen)
            print("resultString : ", resultString)
            print("====================================")
            print("")
        }

        // network 통신 실행
        dataTask.resume()
    }
​

​

    func requestPOST_BODY_JSON() {
        // [URL 지정 및 파라미터 값 지정 실시]
        let urlComponents = URLComponents(string: "https://jsonplaceholder.typicode.com/posts")
        let dicData = ["userId":1, "id":1] as Dictionary<String, Any>? // 딕셔너리 사용해 json 데이터 만든다
        let jsonData = try! JSONSerialization.data(withJSONObject: dicData!, options: [])
        
        // [http 통신 타입 및 헤더 지정 실시]
        var requestURL = URLRequest(url: (urlComponents?.url)!)
        requestURL.httpMethod = "POST" // POST
        requestURL.addValue("application/json", forHTTPHeaderField: "Content-Type") // POST
        requestURL.httpBody = jsonData // Body 부분에 Json 데이터 삽입 실시

        
        // [http 요쳥을 위한 URLSessionDataTask 생성]
        print("")
        print("====================================")
        print("[requestPOST_BODY_JSON : http post body json 요청 실시]")
        print("url : ", requestURL)
        print("json : ", String(data: jsonData, encoding: .utf8) ?? "")
        print("====================================")
        print("")
        let dataTask = URLSession.shared.dataTask(with: requestURL) { (data, response, error) in

            // [error가 존재하면 종료]
            guard error == nil else {
                print("")
                print("====================================")
                print("[requestPOST_BODY_JSON : http post body json 요청 실패]")
                print("fail : ", error?.localizedDescription ?? "")
                print("====================================")
                print("")
                return
            }

            // [status 코드 체크 실시]
            let successsRange = 200..<300
            guard let statusCode = (response as? HTTPURLResponse)?.statusCode, successsRange.contains(statusCode)
            else {
                print("")
                print("====================================")
                print("[requestPOST_BODY_JSON : http post body json 요청 에러]")
                print("error : ", (response as? HTTPURLResponse)?.statusCode ?? 0)
                print("msg : ", (response as? HTTPURLResponse)?.description ?? "")
                print("====================================")
                print("")
                return
            }

            // [response 데이터 획득, json 형태로 변환]
            let resultCode = (response as? HTTPURLResponse)?.statusCode ?? 0
            let resultLen = data! // 데이터 길이
            do {
                guard let jsonConvert = try JSONSerialization.jsonObject(with: data!) as? [String: Any] else {
                    print("")
                    print("====================================")
                    print("[requestPOST_BODY_JSON : http post body json 요청 에러]")
                    print("error : ", "json 형식 데이터 convert 에러")
                    print("====================================")
                    print("")
                    return
                }
                guard let JsonResponse = try? JSONSerialization.data(withJSONObject: jsonConvert, options: .prettyPrinted) else {
                    print("")
                    print("====================================")
                    print("[requestPOST_BODY_JSON : http post body json 요청 에러]")
                    print("error : ", "json 형식 데이터 변환 에러")
                    print("====================================")
                    print("")
                    return
                }
                guard let resultString = String(data: JsonResponse, encoding: .utf8) else {
                    print("Error: Couldn't print JSON in String")
                    print("")
                    print("====================================")
                    print("[requestPOST_BODY_JSON : http post body json 요청 에러]")
                    print("error : ", "json 형식 데이터 >> String 변환 에러")
                    print("====================================")
                    print("")
                    return
                }
                print("")
                print("====================================")
                print("[requestPOST_BODY_JSON : http post body json 요청 성공]")
                print("resultCode : ", resultCode)
                print("resultLen : ", resultLen)
                print("resultString : ", resultString)
                print("====================================")
                print("")
            } catch {
                print("")
                print("====================================")
                print("[requestPOST_BODY_JSON : http post body json 요청 에러]")
                print("error : ", "Trying to convert JSON data to string")
                print("====================================")
                print("")
                return
            }
        }

        // network 통신 실행
        dataTask.resume()
    }

[ 결과 출력 ]

 

 

 

'- IOS > swift' 카테고리의 다른 글

ios view controller 생명주기 (life-cycle)  (0) 2023.09.12
xcode remove reference 한 파일 복구 하기  (0) 2022.09.22
앱 아이콘 설정하기  (0) 2022.04.26
Inout 키워드  (0) 2022.04.20
Argument Label  (0) 2022.04.20