使用Unity在C#中发送HTTP请求

40
如何在Unity中使用C#发送HTTP GET和POST请求?
我想要的是:
- 在POST请求中发送JSON数据(我使用Unity序列化器,所以不需要新的序列化器,我只想传递一个字符串作为POST数据,并且能够设置ContentType为application/json); - 能够轻松获取响应代码和响应内容; - 异步执行所有操作,而不会阻塞UI渲染。
我尝试过的方法有:
- 使用HttpWebRequest/HttpWebResponse实现,但它太复杂和底层(如果找不到更好的方法,我将不得不使用它); - 使用Unity的WWW,但它不符合我的要求; - 使用一些来自NuGet的外部包 - Unity不接受它们。
大部分问题都与线程有关,我在C#中对此还不够熟练。 我使用的IDE是Intellij Rider。

3
使用 HttpClient - DGibbs
如果你想异步执行这个操作,你应该使用Unity提供的WWW和IEnumerator。如果这不是你想要的,那么就编写自己的带有线程的HttpClient,但这很复杂。 - Markiian Benovskyi
{btsdaf} - Sir
1
你可以在Unity中使用NuGet包,查看这个开源插件来使用Promise而不是协程 https://github.com/proyecto26/RestClient - jdnichollsc
4个回答

110
WWW API已经过时,现在应该使用UnityWebRequest来完成这个任务。它非常简单。你必须使用协程来使用Unity的API,否则你必须使用C#标准的Web请求API和线程。使用协程可以让你在请求完成之前挂起它。这不会阻塞主线程或防止其他脚本运行。

注意:

对于以下示例,如果您使用的是低于Unity 2017.2的版本,请用Send()替换SendWebRequest(),然后用isError替换isNetworkError。这将适用于低版本的Unity。此外,如果您需要以二进制形式访问下载的数据,请将uwr.downloadHandler.text替换为uwr.downloadHandler.data。最后,SetRequestHeader函数用于设置请求的头部。

GET请求:

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);
    }
}

使用Json的POST请求:

 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);
     }
 }

使用Multipart FormData/Multipart Form File的POST请求:

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");
    }
}

3
就像我说的,UnityWebRequest 被实现为在另一个线程中运行。协程被用来等待/暂停直到请求完成。yield 等同于等待 UnityWebRequest 完成请求,而它是在另一个线程上运行的。在等待期间,它不会阻塞主线程。这就是为什么协程很棒的原因。 - Programmer
2
我的示例展示了如何进行http请求,还包括使用json。如果您将json示例复制粘贴到您的编辑器中而不需要修改它,它应该可以正常工作。如果您修改它但是它无法工作,请创建一个新问题。在创建新问题之前,我想告诉您,在您的代码中发现的问题是:execute是协程函数,不应像您所做的那样直接调用它。它应该使用StartCoroutine(execute())函数进行调用。再次查看我的示例。您必须添加yield return uwr.SendWebRequest(),否则您将在未来遇到问题。 - Programmer
2
最后,具有协程(execute)函数的类在使用StartCoroutine函数启动协程函数之前必须继承自MonoBehaviour。您的类没有继承自MonoBehaviour。如果您不想继承自MonoBehaviour,请查看我的答案这里,因为我描述了如何不需要继承自MonoBehaviour来完成此操作。在回复此评论之前,请修复所有这些问题。如果遇到问题,请提出一个新问题,但在该问题中发布您的代码。 - Programmer
2
@Bluetree 是的,它应该可以在 Unity 支持的任何平台上运行。 - Programmer
2
@Bluetree,我的回答中已经有了。请看第二个下面的MultipartFormFileSection。在这里可以看到它的许多构造函数重载链接 - Programmer
显示剩余10条评论

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;
    }

Payload是要序列化为json的对象。如果所有请求都将发送到相同的baseUrl,则可以全局设置HttpClient,并在此处重复使用它。


看起来很清晰。我会尝试一下。但是异步执行怎么办? - Kamo Spertsian
请求结束时的.Result是使其同步的关键。如果您删除它,可以使用任务/等待等。 - Jonathan
找不到 HttpClient 类...而且 System.Net.Http 包不存在。 - Kamo Spertsian
2
是的,目前在.NET Framework(3.5)的当前版本中无法使用Unity中的HttClient类。 - jdnichollsc
1
{btsdaf} - Sir
显示剩余2条评论

0

0
我们可以使用WWWUnityWebRequest类来发起API调用。现在WWW已经过时,Unity建议使用UnityWebRequest代替WWW
void Start() {
    string url = "https://retrofit-backend-demo.herokuapp.com/book";
    StartCoroutine(GetBooksUsingWWW(url));
    StartCoroutine(GetBooksUsingUnityWebRequest(url));
}

IEnumerator GetBooksUsingWWW(string url) {
    using (WWW www = new WWW(url)){
        yield return www;
        Debug.Log(www.text);
        JSONNode jsonNode = JSON.Parse(www.text);
        string title = jsonNode[0]["title"].ToString();
        Debug.Log("Title: " + title);
    }
}

IEnumerator GetBooksUsingUnityWebRequest(string url) {
    UnityWebRequest www = UnityWebRequest.Get(url);
    yield return www.SendWebRequest();

    if(www.isNetworkError || www.isHttpError) {
        Debug.Log(www.error);
    }
    else {
        Debug.Log(www.downloadHandler.text);
        JSONNode jsonNode = JSON.Parse(www.downloadHandler.text);
        string title = jsonNode[0]["title"].ToString();
        Debug.Log("Title: " + title);
    }
}

演示用:https://github.com/codemaker2015/api-interaction-unity3d-demo


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接