您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
235 行
8.3 KiB
235 行
8.3 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using Newtonsoft.Json;
|
|
using UnityEngine;
|
|
using UnityEngine.Networking;
|
|
|
|
namespace Unity.Services.Authentication.Utilities
|
|
{
|
|
interface IWebRequest<T>
|
|
{
|
|
event Action<IWebRequest<T>> Completed;
|
|
bool RequestFailed { get; }
|
|
bool NetworkError { get; }
|
|
bool ServerError { get; }
|
|
string ErrorMessage { get; }
|
|
T ResponseBody { get; }
|
|
long ResponseCode { get; }
|
|
IDictionary<string, string> ResponseHeaders { get; }
|
|
}
|
|
|
|
enum WebRequestVerb
|
|
{
|
|
Get,
|
|
Post,
|
|
Put,
|
|
Delete
|
|
}
|
|
|
|
class WebRequest<T> : IWebRequest<T>
|
|
{
|
|
const int k_DefaultTimeoutSeconds = 10;
|
|
const int k_RetryBackoffSeconds = 10;
|
|
|
|
readonly IScheduler m_Scheduler;
|
|
readonly ILogger m_Logger;
|
|
readonly WebRequestVerb m_Verb;
|
|
readonly string m_Url;
|
|
readonly IDictionary<string, string> m_Headers;
|
|
readonly string m_Payload;
|
|
readonly string m_PayloadContentType;
|
|
readonly int m_RedirectLimit;
|
|
int m_Attempts;
|
|
|
|
public event Action<IWebRequest<T>> Completed;
|
|
public bool RequestFailed { get; private set; }
|
|
public bool NetworkError { get; private set; }
|
|
public bool ServerError { get; private set; }
|
|
public string ErrorMessage { get; private set; }
|
|
public T ResponseBody { get; private set; }
|
|
public long ResponseCode { get; private set; }
|
|
public IDictionary<string, string> ResponseHeaders { get; private set; }
|
|
|
|
internal int RequestTimeout { get; set; }
|
|
|
|
internal WebRequest(IScheduler scheduler,
|
|
ILogger logger,
|
|
WebRequestVerb verb,
|
|
string url,
|
|
IDictionary<string, string> headers,
|
|
string payload,
|
|
string payloadContentType,
|
|
int redirectLimit,
|
|
int attempts)
|
|
{
|
|
m_Scheduler = scheduler;
|
|
m_Logger = logger;
|
|
m_Verb = verb;
|
|
m_Url = url;
|
|
m_Headers = headers;
|
|
m_Payload = payload;
|
|
m_PayloadContentType = payloadContentType;
|
|
m_RedirectLimit = redirectLimit;
|
|
m_Attempts = attempts;
|
|
|
|
RequestTimeout = k_DefaultTimeoutSeconds;
|
|
}
|
|
|
|
internal void Send()
|
|
{
|
|
UnityWebRequest unityWebRequest;
|
|
switch (m_Verb)
|
|
{
|
|
case WebRequestVerb.Post:
|
|
if (string.IsNullOrEmpty(m_Payload))
|
|
{
|
|
unityWebRequest = UnityWebRequest.Post(m_Url, string.Empty);
|
|
}
|
|
else
|
|
{
|
|
var postBytes = Encoding.UTF8.GetBytes(m_Payload);
|
|
unityWebRequest = new UnityWebRequest(m_Url, UnityWebRequest.kHttpVerbPOST);
|
|
unityWebRequest.uploadHandler = new UploadHandlerRaw(postBytes)
|
|
{
|
|
contentType = m_PayloadContentType
|
|
};
|
|
unityWebRequest.downloadHandler = new DownloadHandlerBuffer();
|
|
}
|
|
|
|
break;
|
|
case WebRequestVerb.Get:
|
|
unityWebRequest = UnityWebRequest.Get(m_Url);
|
|
break;
|
|
case WebRequestVerb.Put:
|
|
if (string.IsNullOrEmpty(m_Payload))
|
|
{
|
|
unityWebRequest = UnityWebRequest.Put(m_Url, string.Empty);
|
|
}
|
|
else
|
|
{
|
|
var putBytes = Encoding.UTF8.GetBytes(m_Payload);
|
|
unityWebRequest = new UnityWebRequest(m_Url, UnityWebRequest.kHttpVerbPUT);
|
|
unityWebRequest.uploadHandler = new UploadHandlerRaw(putBytes)
|
|
{
|
|
contentType = m_PayloadContentType
|
|
};
|
|
unityWebRequest.downloadHandler = new DownloadHandlerBuffer();
|
|
}
|
|
break;
|
|
case WebRequestVerb.Delete:
|
|
unityWebRequest = UnityWebRequest.Delete(m_Url);
|
|
break;
|
|
default:
|
|
unityWebRequest = UnityWebRequest.Get(m_Url);
|
|
break;
|
|
}
|
|
|
|
if (m_Headers != null)
|
|
{
|
|
foreach (var headerAndValue in m_Headers)
|
|
{
|
|
unityWebRequest.SetRequestHeader(headerAndValue.Key, headerAndValue.Value);
|
|
}
|
|
}
|
|
|
|
unityWebRequest.redirectLimit = m_RedirectLimit;
|
|
unityWebRequest.timeout = RequestTimeout;
|
|
|
|
var asyncOperation = unityWebRequest.SendWebRequest();
|
|
asyncOperation.completed += RequestCompleted;
|
|
m_Attempts--;
|
|
}
|
|
|
|
internal void RequestCompleted(AsyncOperation asyncOperation)
|
|
{
|
|
var unityWebRequest = ((UnityWebRequestAsyncOperation)asyncOperation).webRequest;
|
|
|
|
RequestCompleted(unityWebRequest.responseCode,
|
|
RequestHasNetworkError(unityWebRequest),
|
|
RequestHasServerError(unityWebRequest),
|
|
unityWebRequest.error,
|
|
unityWebRequest.downloadHandler?.text,
|
|
unityWebRequest.GetResponseHeaders());
|
|
}
|
|
|
|
internal void RequestCompleted(long responseCode,
|
|
bool hasNetworkError,
|
|
bool hasServerError,
|
|
string errorText,
|
|
string bodyText,
|
|
IDictionary<string, string> headers)
|
|
{
|
|
NetworkError = hasNetworkError;
|
|
ServerError = hasServerError;
|
|
|
|
if (hasNetworkError && m_Attempts > 0)
|
|
{
|
|
m_Logger.Warning("Network error detected, retrying...");
|
|
|
|
m_Scheduler.ScheduleAction(Send, k_RetryBackoffSeconds);
|
|
}
|
|
else
|
|
{
|
|
RequestFailed = hasNetworkError || hasServerError;
|
|
ResponseCode = responseCode;
|
|
if (RequestFailed)
|
|
{
|
|
// If this is a service error rather than a network error, return the response body
|
|
// as that is likely to contain a service-appropriate error message in this case.
|
|
if (hasServerError && !string.IsNullOrEmpty(bodyText))
|
|
{
|
|
ErrorMessage = bodyText;
|
|
}
|
|
else
|
|
{
|
|
ErrorMessage = errorText;
|
|
}
|
|
|
|
m_Logger.Warning("Request completed with error: {0}", ErrorMessage);
|
|
}
|
|
else
|
|
{
|
|
ResponseHeaders = headers;
|
|
|
|
// Check if the response body has any contents to parse
|
|
if (string.IsNullOrEmpty(bodyText))
|
|
{
|
|
m_Logger.Info("Request completed successfully!");
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
ResponseBody = JsonConvert.DeserializeObject<T>(bodyText);
|
|
|
|
m_Logger.Info("Request completed successfully!");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
m_Logger.Warning("Failed to deserialize object!" + ex.Message);
|
|
ErrorMessage = ex.Message;
|
|
RequestFailed = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
Completed?.Invoke(this);
|
|
}
|
|
}
|
|
|
|
bool RequestHasServerError(UnityWebRequest request)
|
|
{
|
|
return request.responseCode >= 400;
|
|
}
|
|
|
|
bool RequestHasNetworkError(UnityWebRequest request)
|
|
{
|
|
#if UNITY_2020_2_OR_NEWER
|
|
return request.result == UnityWebRequest.Result.ConnectionError && request.error != "Redirect limit exceeded";
|
|
#else
|
|
return request.isNetworkError && request.error != "Redirect limit exceeded";
|
|
#endif
|
|
}
|
|
}
|
|
}
|