Отправка HTTP-запросов в С# с помощью Unity

Как я могу отправлять HTTP-запросы GET и POST в С# с Unity?

Что я хочу, это:

  • отправить данные JSON в запросе пост (я использую сериализатор Unity, поэтому нет необходимости в новый, я просто хочу передать строку в данных поста и иметь возможность установите ContentType для application/json);
  • получить код ответа и тело без проблем;
  • делайте все это асинхронно, не блокируя рендеринг пользовательского интерфейса.

Что я пробовал:

  • реализация с HttpWebRequest/HttpWebResponse, но это слишком сложно и на низком уровне (если я не найду ничего лучшего, мне придется его использовать);
  • используя единство WWW, но это не соответствует моим требованиям;
  • используя некоторые внешние пакеты от NuGet - Unity не принимает их :(

Большинство проблем были с многопоточностью, я не достаточно опытен в этом в С#. IDE, я использую, это Intellij Rider.

Ответ 1

WWW API должен это сделать, но UnityWebRequest заменил его, поэтому я отвечу на новый API. Это действительно просто. Вы должны использовать сопрограмму, чтобы сделать это с Unity API, в противном случае вам придется использовать один из стандартных С# API веб-запросов и Thread. С сопрограммой вы можете предоставить запрос, пока он не будет сделан. Это не будет блокировать основной поток или препятствовать запуску других сценариев.

Примечание:

В приведенных ниже примерах, если вы используете что-либо ниже Unity 2017.2, замените SendWebRequest() на Send() а затем замените isNetworkError на isError.Это тогда будет работать для более низкой версии Unity.Кроме того, если вам нужно получить доступ к загруженным данным в двоичном виде, замените uwr.downloadHandler.text на uwr.downloadHandler.data.Наконец, функция SetRequestHeader используется для установки заголовка запроса.

ПОЛУЧИТЬ запрос:

void Start()
{
    StartCoroutine(getRequest("http:///www.yoururl.com"));
}

IEnumerator GetRequest(string uri)
{
    UnityWebRequest uwr = UnityWebRequest.Get(uri);
    yield return uwr.SendWebRequest();

    if (uwr.isNetworkError)
    {
        Debug.Log("Error While Sending: " + uwr.error);
    }
    else
    {
        Debug.Log("Received: " + uwr.downloadHandler.text);
    }
}

POST запрос с формой:

void Start()
{
    StartCoroutine(postRequest("http:///www.yoururl.com"));
}

IEnumerator PostRequest(string url)
{
    WWWForm form = new WWWForm();
    form.AddField("myField", "myData");
    form.AddField("Game Name", "Mario Kart");

    UnityWebRequest uwr = UnityWebRequest.Post(url, form);
    yield return uwr.SendWebRequest();

    if (uwr.isNetworkError)
    {
        Debug.Log("Error While Sending: " + uwr.error);
    }
    else
    {
        Debug.Log("Received: " + uwr.downloadHandler.text);
    }
}

POST запрос с Json:

 void Start()
 {
     StartCoroutine(postRequest("http:///www.yoururl.com", "your json"));
 }

 IEnumerator PostRequest(string url, string json)
 {
     var uwr = new UnityWebRequest(url, "POST");
     byte[] jsonToSend = new System.Text.UTF8Encoding().GetBytes(json);
     uwr.uploadHandler = (UploadHandler)new UploadHandlerRaw(jsonToSend);
     uwr.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
     uwr.SetRequestHeader("Content-Type", "application/json");

     //Send the request then wait here until it returns
     yield return uwr.SendWebRequest();

     if (uwr.isNetworkError)
     {
         Debug.Log("Error While Sending: " + uwr.error);
     }
     else
     {
         Debug.Log("Received: " + uwr.downloadHandler.text);
     }
 }

POST-запрос с Multipart FormData/Multipart Form File:

void Start()
{
    StartCoroutine(postRequest("http:///www.yoururl.com"));
}

IEnumerator PostRequest(string url)
{
    List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
    formData.Add(new MultipartFormDataSection("field1=foo&field2=bar"));
    formData.Add(new MultipartFormFileSection("my file data", "myfile.txt"));

    UnityWebRequest uwr = UnityWebRequest.Post(url, formData);
    yield return uwr.SendWebRequest();

    if (uwr.isNetworkError)
    {
        Debug.Log("Error While Sending: " + uwr.error);
    }
    else
    {
        Debug.Log("Received: " + uwr.downloadHandler.text);
    }
}

Запрос PUT:

void Start()
{
    StartCoroutine(putRequest("http:///www.yoururl.com"));
}

IEnumerator PutRequest(string url)
{
    byte[] dataToPut = System.Text.Encoding.UTF8.GetBytes("Hello, This is a test");
    UnityWebRequest uwr = UnityWebRequest.Put(url, dataToPut);
    yield return uwr.SendWebRequest();

    if (uwr.isNetworkError)
    {
        Debug.Log("Error While Sending: " + uwr.error);
    }
    else
    {
        Debug.Log("Received: " + uwr.downloadHandler.text);
    }
}

УДАЛИТЬ запрос:

void Start()
{
    StartCoroutine(deleteRequest("http:///www.yoururl.com"));
}

IEnumerator DeleteRequest(string url)
{
    UnityWebRequest uwr = UnityWebRequest.Delete(url);
    yield return uwr.SendWebRequest();

    if (uwr.isNetworkError)
    {
        Debug.Log("Error While Sending: " + uwr.error);
    }
    else
    {
        Debug.Log("Deleted");
    }
}

Ответ 2

Используйте HttpClient и что-то вроде:

public static HttpContent DoPost(object payload, string subPath)
    {
        var httpClient = new HttpClient();

        HttpClient.BaseAddress = new Uri(Global.BaseUrl);
        HttpClient.DefaultRequestHeaders.Clear();
        HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); // if you're using json service

        // make request
        var response = Global.HttpClient.PostAsJsonAsync(subPath.TrimLeadingSlash(), payload).Result;

        // check for error
        response.EnsureSuccessStatusCode();

        // return result
        return response.Content;
    }

Полезная нагрузка - это объект, который будет сериализован для json. Если все запросы поступают на тот же baseUrl, вы можете настроить HttpClient глобально и повторно использовать его здесь.