Dictionary<string, string> requestData = new Dictionary<string, string>(packet.data);
UnityWebRequest webRequest = UnityWebRequest.Post(url, requestData);
주로 POST 요청을 보낼 때, 같은 UnityWebRequest 객체를 재사용하거나, 내부적으로 데이터를 다시 읽으려고 하는데 실패했을 때 발생하는 에러
while(RequestQueue.Count > 0)
{
...
...
UnityWebRequest webRequest = UnityWebRequest.Post(url, packet.data);
}
이렇게 쓰면 packet.data가 새 객체가 되어서 요청 가능한 상태가 되는 줄 알았는데 아니였음.
저 한줄에서 wepRequest는 새 객체가 된것이 맞으나 요청할때는 재사용으로 들어가버림.
UnityWebRequest.Post(url, packet.data) 이걸 반복 호출하는데 packet.data가 WWWForm 같은 stateful 객체면, 내부 스트림이 이미 닫혀서 "rewind"가 안 되는 것이된다. → Curl error 65
UnityWebRequest.Post(url, packet.data)
이거는 내부적으로 packet.data를 바탕으로 UploadHandler를 만들어서 stream으로 보낸 후, 그 stream을 재사용하려고 하면서 터진다.
결론
=> packet.data를 매 요청마다 새로 만든다. +(using문으로 개선.)
A. Dictionary<string, string> 인 경우.
var originalData = packet.data;
var dataCopy = new Dictionary<string, string>(originalData);
using (UnityWebRequest webRequest = UnityWebRequest.Post(url, dataCopy))
{
yield return webRequest.SendWebRequest();
}
B. byte[] 인 경우.
var originalData = packet.data;
var dataCopy = new byte[originalData.Length];
Buffer.BlockCopy(originalData, 0, dataCopy, 0, originalData.Length);
using (UnityWebRequest webRequest = new UnityWebRequest(url, "POST"))
{
webRequest.uploadHandler = new UploadHandlerRaw(dataCopy);
webRequest.downloadHandler = new DownloadHandlerBuffer();
webRequest.SetRequestHeader("Content-Type", "application/json");
yield return webRequest.SendWebRequest();
// 나머지 처리...
}
C. WWWForm인 경우
WWWForm CreateForm(Dictionary<string, string> data)
{
var form = new WWWForm();
foreach (var pair in data)
form.AddField(pair.Key, pair.Value);
return form;
}
while (attempt < 3 && !requestSucceeded)
{
var form = CreateForm(packet.data);
UnityWebRequest webRequest = UnityWebRequest.Post(url, form);
Debug.Log($"Request :: {url}\n{packet}");
yield return webRequest.SendWebRequest();
}
Curl error 65 는 주기적으로 같은 요청을 반복할때 주로 난다고 보면됨.
운영에 관여하는 부분이 아니라면 예외처리 해두어서 그냥 넘겨도 괜찮은듯.
(짜피 주기적으로 계속 요청하는데 30번에 1번꼴로 발생하는거라서 팝업을 띄우는게 아닌이상 플레이에 지장이 없음)
+서버가 Json 형식으로 받지 못할수 있음
=> 기존 방식인 UnityWebRequest.Post(url, packet.data) + WWWForm 방식으로 유지하되, rewind(재사용)안되는 방식으로 수정할것. (대부분의 PHP/ASP 서버는 폼타입으로 받음)
+최종 결론 (해결함)
원인은
RequestQueue.Enqueue(Instance.prevPacket);
StartCoroutine(Instance.WaitforRequest());
이렇게 사용했기 때문이고 이유는 isNetworking 플래그가 true로 바뀌기 전에 WaitforRequest가 두번 실행되는 에러로 동시에 같은 packet.data를 사용했기때문에 간헐적으로 rewind 에러가 나온것이다.
중복 호출 방어코드로 수정
RequestQueue.Enqueue(packet);
// 이미 돌고 있으면 새로 안 돌림
if (requestRoutine == null)
requestRoutine = StartCoroutine(WaitforRequest());
var data = new Dictionary<string, string>(packet.data);
byte[] postData = EncodeForm(data); //rewind 방지
using (UnityWebRequest webRequest = new UnityWebRequest(url, "POST"))
{
webRequest.uploadHandler = new UploadHandlerRaw((byte[])postData.Clone());
webRequest.downloadHandler = new DownloadHandlerBuffer();
webRequest.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");
Debug.Log($"Request :: {url}\n{packet}");
yield return webRequest.SendWebRequest();
//내용
}
private static byte[] EncodeForm(Dictionary<string, string> form)
{
string body = string.Join("&", form.Select(kv => $"{UnityWebRequest.EscapeURL(kv.Key)}={UnityWebRequest.EscapeURL(kv.Value)}"));
return Encoding.UTF8.GetBytes(body);
}
'Unity' 카테고리의 다른 글
Render queue value outside of the allowed range (2450 - 2500) for selected Blend mode, resetting render queue to default (0) | 2025.04.16 |
---|---|
image의 기본 Material 수정시 하이라키 전체의 UI/Default 속성이 바뀌는 경우 (0) | 2025.04.15 |
MeshRenderer 의 메쉬가 Text 를 가릴때 (0) | 2025.04.11 |
텍스트 이펙트 패키지 (0) | 2025.04.09 |
Lean.Common; 이슈 (0) | 2025.03.31 |