일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- canvasgroup
- csvhelper
- 전면광고
- unity
- 모션
- cs
- 게임개발
- unity3D
- dotween
- LINQ
- 컴퓨터구조
- climbingtheleaderboard
- 코딩테스트
- 프로그래머스
- Admob
- 유니티기초
- 랜덤
- 열거형
- ui
- React Native
- http
- 유니티
- scrollrect
- 애드몹
- UGUI
- 광고테스트
- 애니메이션
- Hackerrank
- C#
- enum
- Today
- Total
Ruya Games
[UniTask] 유니티 HTTP통신 구현 코드(+bearer token 사용) 본문
가끔 서버와의 HTTP 통신을 구현해야 할때가 있습니다.
아래는 간단히 Post, Get을 사용할 수 있도록 하는 코드입니다.
비동기 호출을 UniTask를 사용해서 구현했는데, 그냥 async를 사용하셔도 됩니다. 다만 async보다는 UniTask가 성능이 좋습니다.
(UniTask의 자세한 설명 & 다운로드는 여기서 가능합니다. -> https://github.com/Cysharp/UniTask)
구현 코드가 길지만 사용은 간단합니다 :)
(전체코드는 맨 밑에 있습니다.)
일단 UnityWebRequest로 Post, Get을 호출하는 함수를 작성합니다.
private async UniTask<T> Post<T>(string action, Request data) where T : Response {
var cts = new CancellationTokenSource();
cts.CancelAfterSlim(TimeSpan.FromSeconds(5));
using UnityWebRequest req = UnityWebRequest.Post($"{serverUrl}{action}", data.GetForm());
try {
var res = await req.SendWebRequest().WithCancellation(cts.Token);
var responseString = res.downloadHandler.text;
return JsonConvert.DeserializeObject<T>(responseString);
} catch (UnityWebRequestException e) {
return JsonConvert.DeserializeObject<T>(e.Text);
}
}
private async UniTask<T> Get<T>(string action, Request data) where T : Response {
var cts = new CancellationTokenSource();
cts.CancelAfterSlim(TimeSpan.FromSeconds(5));
using var req = UnityWebRequest.Get($"{serverUrl}{action}");
try {
var res = await req.SendWebRequest().WithCancellation(cts.Token);
var responseString = res.downloadHandler.text;
return JsonConvert.DeserializeObject<T>(responseString);
} catch (UnityWebRequestException e) {
return JsonConvert.DeserializeObject<T>(e.Text);
}
}
위의 코드에 대해 설명을 해보겠습니다.
CancellationTokenSource는 호출의 시간제한을 두기 위해 생성하고, WithCancellation()함수에 인자로 넣어 사용합니다.
일단 Response와 Request 클래스는 전달, 전송시의 값을 저장하기 위해 임의로 만든 클래스입니다. 기본적인 구조는 다음과 같습니다.
public class Response {
public int status;
public string message;
public string server;
}
public class Request {
public int id;
public WWWForm GetForm() {
WWWForm form = new WWWForm();
var fields = this.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (var field in fields) {
if (field.FieldType == typeof(int)) {
form.AddField(field.Name, (int)field.GetValue(this));
}
else if (field.FieldType == typeof(string)) {
form.AddField(field.Name, (string)field.GetValue(this));
}
}
return form;
}
}
Request에 있는 GetForm()함수는, 클래스 형식으로 저장된 전송값을 WWWForm으로 변경해주는 함수입니다.
전송, 전달 형식에 맞춰서 Request, Response클래스의 변수들을 작성해서 사용하시면 됩니다.
통신의 response로 실패를 전달받게되면 exception이 발생하면서 catch문으로 빠지는데요. 이때도 동일한 형식의 클래스로 리턴하려면 보통 UnityWebRequestException 인스턴스의 .Text 값을 받아서 역직렬화에 사용하시면 됩니다.
제너릭 함수로 구현한 이유는 전송, 전달 형식이 달라져도 Request와 Response의 상속을 통해 대응할 수 있도록 하기 위함입니다.
+여기서 bearer 토큰을 사용한 인증방식을 추가하신다면, 헤더에 아래처럼 토큰값을 넣어주시면 됩니다.
using var req = UnityWebRequest.Get($"{serverUrl}{action}");
req.SetRequestHeader("Authorization", $"Bearer {token}"); // bearer token 추가 부분
var res = await req.SendWebRequest().webRequest;
이후, Post와 Get을 호출하는 부분을 하나의 메소드로 통일합니다. 아래는 그 메소드입니다.
private async UniTask<T> Process<T>(Method method, string action, Action<T> onSuccess, Action<T> onFailure, Request2 request = null) where T : Response {
var result = method switch {
Method.GET => await Post<T>(action, request),
Method.POST => await Get<T>(action, request),
_ => throw new ArgumentOutOfRangeException(nameof(method), method, null)
};
if(/*에러 판별*/result.status < 400) onSuccess?.Invoke(result);
else onFailure?.Invoke(result);
return result;
}
이 메소드는 enum타입인 Method값을 통해 Get인지, Post인지 확인한 뒤에 값에 맞게 Get또는 Post를 실행시킵니다.
이후 성공/실패 여부를 확인해야하는데요. 저같은 경우는 status값이 400 이하일때 성공이기 때문에 이걸로 콜의 성공/실패 여부를 판별했습니다.
성공했다면 onSuccess를 실행하고, 실패했다면 onFailure를 실행하게 됩니다. 각각 성공, 실패시에 처리할 이벤트를 함수형식으로 입력해주시면 됩니다.
사실 다르게 구현하셔도 됩니다. 공통되는 부분이 많기에, Post와 Get을 따로 함수를 구분하지 않고 하나의 함수로 구현하셔도 되고(그럴 경우에는 UnityWebRequest('url', 'method')방식으로 웹리퀘스트 인스턴스를 생성하시는게 더 가독성이 좋을것 같습니다), Process라는 함수를 특별히 경유하지 않도록 해도 됩니다. 이렇게 굳이 분리해서 구현한것은 그저 제 취향입니다.
이제 Post또는 Get을 하고싶다면, Process()를 호출하면 됩니다. 아래는 사용예입니다.
var response = await Process<Response>(
Method.POST,
"/getInfo",
SuccessAction,
FailureAction,
new Request2() { /*여기에 값 추가*/});
}
public void SuccessAction(Response re) {
//성공시 실행할 코드
}
public void FailureAction(Response re) {
//실패시 실행할 코드
}
구현부의 전체 코드는 다음과 같습니다.
public enum Method {GET, POST}
public class Response {
public int status;
public string message;
public string server;
}
public class Request {
public int id;
public WWWForm GetForm() {
WWWForm form = new WWWForm();
var fields = this.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (var field in fields) {
if (field.FieldType == typeof(int)) {
form.AddField(field.Name, (int)field.GetValue(this));
}
else if (field.FieldType == typeof(string)) {
form.AddField(field.Name, (string)field.GetValue(this));
}
}
return form;
}
}
public class NetworkCall {
public string serverUrl = "https://서버 주소";
private async UniTask<T> Post<T>(string action, Request data) where T : Response {
var cts = new CancellationTokenSource();
cts.CancelAfterSlim(TimeSpan.FromSeconds(5));
using UnityWebRequest req = UnityWebRequest.Post($"{serverUrl}{action}", data.GetForm());
try {
var res = await req.SendWebRequest().WithCancellation(cts.Token);
var responseString = res.downloadHandler.text;
return JsonConvert.DeserializeObject<T>(responseString);
} catch (UnityWebRequestException e) {
return JsonConvert.DeserializeObject<T>(e.Text);
}
}
private async UniTask<T> Get<T>(string action, Request data) where T : Response {
var cts = new CancellationTokenSource();
cts.CancelAfterSlim(TimeSpan.FromSeconds(5));
using var req = UnityWebRequest.Get($"{serverUrl}{action}");
try {
var res = await req.SendWebRequest().WithCancellation(cts.Token);
var responseString = res.downloadHandler.text;
return JsonConvert.DeserializeObject<T>(responseString);
} catch (UnityWebRequestException e) {
return JsonConvert.DeserializeObject<T>(e.Text);
}
}
private async UniTask<T> Process<T>(Method method, string action, Action<T> onSuccess, Action<T> onFailure, Request2 request = null) where T : Response {
var result = method switch {
Method.GET => await Post<T>(action, request),
Method.POST => await Get<T>(action, request),
_ => throw new ArgumentOutOfRangeException(nameof(method), method, null)
};
if(/*에러 판별*/result.message == null) onSuccess?.Invoke(result);
else onFailure?.Invoke(result);
return result;
}
}
'Unity' 카테고리의 다른 글
유니티에서 텍스트 타이핑 대사박스 효과 구현하기 (1) | 2023.12.07 |
---|---|
유니티 자식 순서 받아오기 & 변경하기(Transform) (1) | 2023.12.07 |
에디터상에서 윈도우 추가하기 (0) | 2023.12.06 |
게임 일시정지 하는 방법 + 속도 조절하는법 (0) | 2023.12.06 |
Unity In-App Purchasing 설정 - Google License Key 위치 (0) | 2023.12.05 |