Other/Unity

[Unity] HttpWebRequest와 JsonUtility를 사용하여 웹 서버와 통신하고 POST 방식으로 json 데이터 가져오기

개발왕 금골드 2020. 2. 13. 20:20
반응형

안녕하세요 골드입니다.

오늘은 Unity에서 웹 서버와 통신하여 json 데이터를 POST 방식으로 불러오는 방법에 대해서 글을 쓰도록 하겠습니다.

최근에(혹은 이전부터 이미) 어플리케이션을 만들 때, JSON데이터를 사용하는 방식은 

아주 인기 있는 방식입니다. 여러가지 예를 들 수 있겠습니다만,

공공데이터를 활용할 때 가장 유용하게 쓰이는 방식입니다. 

JSON 형식으로 데이터를 불러와서 사용하는 방식의 특징은 프론트와 백이 철저히 분리되어 있기 때문에 유지보수가 용이하다고 할 수 있겠습니다.

 

그럼 조금 더 알아보겠습니다.

1. JSON 데이터

 - JSON(JavaScript Object Nation)은 경량의 데이터 교환 형식입니다.

 - JavaSctipt에서 객체를 만들 때 사용하는 표현식을 의미합니다.

 - JSON 표현식은 사람과 기계 모두 이해하기 쉽고, 용량이 작아서 최근에 XML을 대체해서 데이터 전송 등에 많이 사용됩니다.

 - 대부분의 프로그래밍 언어에서 JSON 데이터를 핸들링할 수 있는 라이브러리를 제공합니다.

 

JSON 데이터 형식

 

key - value 형식의 쌍으로 이루어져 있습니다.

 

key를 올바르게 입력해야만 value를 얻을 수 있습니다.

자물쇠같이 말입니다.

모두 string 값이지만 int도 가능합니다 예를 들어 "gender" : 1

변수들을 String, int, array, list 등 다양한 형식으로 선언할 수 있으며,

다양한 프로그래밍 언어에서 구현할 수 있다는 장점이 있습니다.

 

2. JSON 데이터를 보내고 받기 위한 CLASS 생성

Unity에서 C# 파일을 하나 만듭니다.

 

 

HttpWebRequest를 사용하기 위해 System.Net을 선언하고,

StreamReader를 사용하기 위해 System.IO를 선언합니다.

 

Class를 선언할 때,  Json 데이터와 딱 맞아야됩니다.

가령, 이미지 속 데이터를 보낸다고 가정하면,

 

이런식으로 자료형과 변수 이름이 딱 맞아 떨어져야합니다.

어떤 언어(혹은 툴)이냐에 차이가 있을 수 있지만,

스펠링이 틀렸을 때 에러는 발생되지 않고 값을 제대로 가져오지 못하는 경우가 있을 수 있습니다.

이런 경우에 스펠링이 틀려서 발생한 오류라는 것을 쉽게 인지하기 어려울 수 있습니다.

 

관리를 위해 System.Serializable을 작성합니다.

 

커스텀 클래스가 구조체처럼 동작할 때

UnityEngine.Object에서 파생되지 않은 커스텀 클래스는 Unity 에디터에서 구조체가 직렬화되는 방법과 비슷하게 값에 따라 인라인에서 직렬화됩니다. 커스텀 클래스의 인스턴스에 대한 레퍼런스를 여러 다른 필드에 저장하면 직렬화할 때 별도의 오브젝트가 됩니다. 그 후 Unity 에디터가 필드를 역직렬화하면 데이터가 똑같은 여러 개의 개별 오브젝트가 필드에 포함됩니다.

출처 : https://docs.unity3d.com/kr/2018.4/Manual/script-Serialization.html

 

스크립트 직렬화 - Unity 매뉴얼

직렬화는 데이터 구조나 오브젝트 상태를 Unity 에디터가 저장하고 나중에 재구성할 수 있는 포맷으로 자동으로 변환하는 프로세스를 말합니다. Unity 에디터에서는 저장 및 로딩, 인스펙터 창, 인

docs.unity3d.com

 

 

마찬가지로 데이터를 받을 때를 위한 class도 json 데이터 형식과 정확하게 일치해야 합니다.

 

먼저 JSON 형식에서 가장 상위에 선언되어 있는 변수 세 개를 유니티에서 선언했습니다.

"result" : [ ]. 대괄호로 되어 있기 때문에 List를 사용했고,

그 안에(MemberDataDetail) "name", "gender", "email" 이 선언되어 있습니다.

 

주의할 점은 [ ]로 선언된 부분을 List로 선언했다는 점과 

[ ] 안에 있는 값을 위한 class를 또 따로 만들어줘야 한다는 점입니다.

그 외에 ""로 선언되었기 때문에 string 자료형을 선언한 점은 보면 알 수 있습니다.

("code" : "0" 는 ""안에 0을 선언하였기 때문에 string 입니다.)

(만약 "code" : 0 이었다면 int로 선언했을 것입니다.)

 

두 클래스 모두 MonoBehavior를 상속할 필요 없다는 점을 참고하세요.

 

3. 실제 통신을 위한 Class 작성하기

 

위에 [Serializable]이 붙은 class는 모두 JSON에 맞추기 위해 선언한 class입니다.

(3개 정도면 상당히 적은 편이라고 생각합니다.)

 

제 코드입니다. 저는 간단한 코드이기 때문에 JsonExample이라는 파일에 다 작성했습니다.

JsonExample class에서 통신을 위한 코드를 작성할 것입니다.

먼저 baseURL을 선언했습니다. 여기에 여러분의 웹 주소를 작성하면 됩니다.

 

(주소를 작성할 때 http:// 혹은 https://로 작성할텐데요, 최근에 모든 웹사이트가 https://를 사용하도록 권장하고 있습니다. 그런데 간혹 https://를 사용했을 때 에러가 나는 경우가 있습니다. 맨 밑에 해당 사항에 대해서 간단히 정리해 보았습니다.)

 

 

 

 

HTTP 트랜잭션의 일반 코드 플로우입니다.

지금부터 작성할 코드에 대한 차트라고 보면 되겠습니다.

  • 웹 요청 오브젝트 생성

출처 : https://docs.unity3d.com/kr/2019.3/Manual/UnityWebRequest.html

 

저는 UnityWebRequest가 아닌 HttpWebRequest를 사용하고 있습니다.

그리고 데이터를 byte stream 형태로 보내고, 받고 있습니다.

 

이제 GetMemeberData()를 Start() 밑에 작성합니다. (오타는 신경쓰지 않습니다.)

 

 

GetMemeberData() 메서드의 전체 코드입니다.

여러분의 코드에 맞게 작성해주세요.

 

먼저 요청 보낼 데이터를 정의합니다.

정의한 데이터를 JsonUtility를 사용해서 json 형식으로 보낼 데이터를

string 값으로 변환한 후 다시 byte[] 형태로 인코딩합니다.

(string 형태로는 보낼 수 없기 때문입니다.)

 

그 다음은 요청 보낼 주소와 몇 가지 세팅을 정의합니다.

먼저 요청 보낼 주소를 작성하고 방식은 POST 방식입니다.

요청 보낼 content 데이터에 대해서도 정의합니다.

 

요청 스트림으로 byte[] stream을 보냅니다.

byte의 길이만큼 보낸 후 혹시라도 다음에 스트림을 사용할 때

찌꺼기가 남아있지 않도록 Flush()를 사용한 후 메모리 누수를 방지하기 위해 close해줍니다.

(Stream을 사용하면 항상 Close()해줘야 한다는 점은 중요합니다.)

이제 스트림으로 보낸 데이터에 대한 value를 받습니다.

마찬가지로 StreamReader를 사용해서 스트림 값을 읽어옵니다.

읽어 온 stream값을 string 형태로 변환하여 사용하기 편하게 만들어줍니다.

(현재 string값은 사용하기 불편하게 모든 데이터가 일렬로 되어있습니다.)

처음에 보냈던 모습과 마찬가지로 class에 정의한 변수대로 받아서

사용할 수 있도록 JsonUtility로 읽어줍니다.

 

이런 과정을 거쳐야 데이터를 보내고 받아서 class 변수처럼 사용할 수 있습니다.

 

JsonUtility를 사용하면 Json <-> Object로 변환할 수 있습니다.

 

 

 

로그에 success라고 찍히는 것을 볼 수 있습니다.

이 success는

info.message로 "message" 데이터를 가져왔기 때문입니다.

(위에 이미지 참고)

 

여기까지 골드였습니다.

감사합니다.

 

----------------------------------------------------------------------------------------

* 추가 2020.04.23

SSL 오류

웹서버에서 사용중인 SSL 인증서가 정상적이지 않은 경우

SevicePointManager.ServerCertificateValidationCallback이라는 것이 발생합니다.

따라서 해당 부분을 무시하는 코드를 작성해야 하는데요,

GetMemberData() 메서드에서 요청 보낼 주소를 세팅하는 부분에

이 코드를 한 줄 작성해주세요.

 

제일 좋은 방법은 SSL을 확인하는 것입니다.

 

 

참고자료 : https://nesoy.github.io/articles/2017-02/JSON

https://c10106.tistory.com/2588

 

반응형