C# 一种在 Unity iOS 上发出 HTTP 请求的方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12224602/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
A method for making HTTP requests on Unity iOS?
提问by fordeka
I need to send HTTP requests with all the standard RESTful methods and access to the body of the request in order to send/receive JSON with it. I've looked into,
我需要使用所有标准 RESTful 方法发送 HTTP 请求并访问请求正文,以便使用它发送/接收 JSON。我调查过,
WebRequest.HttpWebRequest
WebRequest.HttpWebRequest
This works almost perfectly, but there are cases where, for example, if the server is down the function GetResponse can take several seconds to return- since it is a synchronous method- freezing the application for that period. The asynchronous version of this method, BeginGetResponse, does not seem to work asynchronously (in Unity anyway) as it still freezes the application for that period.
这几乎可以完美运行,但在某些情况下,例如,如果服务器关闭,函数 GetResponse 可能需要几秒钟才能返回 - 因为它是一种同步方法 - 在那段时间内冻结应用程序。此方法的异步版本 BeginGetResponse 似乎无法异步工作(无论如何在 Unity 中),因为它在该期间仍会冻结应用程序。
UnityEngine.WWW#
UnityEngine.WWW#
Only supports POST and GET requests for some reason- but I also need PUT and DELETE (standard RESTful methods) so I didn't bother looking into it any further.
出于某种原因只支持 POST 和 GET 请求——但我还需要 PUT 和 DELETE(标准 RESTful 方法),所以我没有进一步研究它。
System.Threading
系统线程
In order to run WebRequest.HttpWebRequest.GetResponse without freezing the application I looked into using threads. Threads seem to work in the editor (but seem extremely volatile- if you don't stop a thread when the application exits it keeps running in the editor forever even when you stop it), and when built to an iOS device crash it as soon as I try to start a thread (I forgot to write down the error and I don't have access to it right now).
为了在不冻结应用程序的情况下运行 WebRequest.HttpWebRequest.GetResponse,我研究了使用线程。线程似乎在编辑器中工作(但似乎非常不稳定 - 如果您在应用程序退出时不停止线程,即使您停止它,它也会永远在编辑器中运行),并且当内置到 iOS 设备时它会尽快崩溃当我尝试启动一个线程时(我忘记写下错误,我现在无法访问它)。
Run threads in a native iOS app with a bridge to the Unity app
通过连接到 Unity 应用程序的桥接器在本机 iOS 应用程序中运行线程
Ridiculous, not even going to attempt this.
可笑,甚至不打算尝试这个。
UniWeb
万维网
This. I would like to know how they managed it.
这个。我想知道他们是如何管理的。
Here is an example of the WebRequest.BeginGetResponse method I am trying,
这是我正在尝试的 WebRequest.BeginGetResponse 方法的示例,
// The RequestState class passes data across async calls.
public class RequestState
{
const int BufferSize = 1024;
public StringBuilder RequestData;
public byte[] BufferRead;
public WebRequest Request;
public Stream ResponseStream;
// Create Decoder for appropriate enconding type.
public Decoder StreamDecode = Encoding.UTF8.GetDecoder();
public RequestState()
{
BufferRead = new byte[BufferSize];
RequestData = new StringBuilder(String.Empty);
Request = null;
ResponseStream = null;
}
}
public class WebRequester
{
private void ExecuteRequest()
{
RequestState requestState = new RequestState();
WebRequest request = WebRequest.Create("mysite");
request.BeginGetResponse(new AsyncCallback(Callback), requestState);
}
private void Callback(IAsyncResult ar)
{
// Get the RequestState object from the async result.
RequestState rs = (RequestState) ar.AsyncState;
// Get the WebRequest from RequestState.
WebRequest req = rs.Request;
// Call EndGetResponse, which produces the WebResponse object
// that came from the request issued above.
WebResponse resp = req.EndGetResponse(ar);
}
}
... based on this: http://msdn.microsoft.com/en-us/library/86wf6409(v=vs.71).aspx
...基于此:http: //msdn.microsoft.com/en-us/library/86wf6409(v=vs.71).aspx
采纳答案by fordeka
I got threading to work on iOS- I believe it was crashing due to ghost threads or something. Restarting the device seems to have fixed the crashing so I'll just use WebRequest.HttpWebRequest with threads.
我让线程在 iOS 上工作 - 我相信它是由于幽灵线程或其他原因而崩溃的。重新启动设备似乎已经解决了崩溃问题,所以我将只使用 WebRequest.HttpWebRequest 和线程。
回答by cregox
Ok, I finally managed to write my own solution. We basically need a RequestState, a Callback Methodand a TimeOut Thread. Here I'll just copy what wasdone in UnifyCommunity(now called unity3d wiki). This is outdated code, but smaller than what's there, so more convenient to show something here. Now I've removed (in the unit3d wiki) System.Actionand staticfor performance and simplicity:
好的,我终于设法编写了自己的解决方案。我们基本上需要一个RequestState,一个Callback Method和一个TimeOut Thread。在这里我就复制什么是在UnifyCommunity做(现在叫unity3d维基)。这是过时的代码,但比那里的代码小,所以在这里展示一些东西更方便。现在我已经删除了(在 unit3d wiki 中)System.Action并且static为了性能和简单性:
Usage
用法
static public ThisClass Instance;
void Awake () {
Instance = GetComponent<ThisClass>();
}
static private IEnumerator CheckAvailabilityNow () {
bool foundURL;
string checkThisURL = "http://www.example.com/index.html";
yield return Instance.StartCoroutine(
WebAsync.CheckForMissingURL(checkThisURL, value => foundURL = !value)
);
Debug.Log("Does "+ checkThisURL +" exist? "+ foundURL);
}
WebAsync.cs
WebAsync.cs
using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Collections;
using UnityEngine;
/// <summary>
/// The RequestState class passes data across async calls.
/// </summary>
public class RequestState
{
public WebRequest webRequest;
public string errorMessage;
public RequestState ()
{
webRequest = null;
errorMessage = null;
}
}
public class WebAsync {
const int TIMEOUT = 10; // seconds
/// <summary>
/// If the URLs returns 404 or connection is broken, it's missing. Else, we suppose it's fine.
/// </summary>
/// <param name='url'>
/// A fully formated URL.
/// </param>
/// <param name='result'>
/// This will bring 'true' if 404 or connection broken and 'false' for everything else.
/// Use it as this, where "value" is a System sintaxe:
/// value => your-bool-var = value
/// </param>
static public IEnumerator CheckForMissingURL (string url, System.Action<bool> result) {
result(false);
Uri httpSite = new Uri(url);
WebRequest webRequest = WebRequest.Create(httpSite);
// We need no more than HTTP's head
webRequest.Method = "HEAD";
RequestState requestState = new RequestState();
// Put the request into the state object so it can be passed around
requestState.webRequest = webRequest;
// Do the actual async call here
IAsyncResult asyncResult = (IAsyncResult) webRequest.BeginGetResponse(
new AsyncCallback(RespCallback), requestState);
// WebRequest timeout won't work in async calls, so we need this instead
ThreadPool.RegisterWaitForSingleObject(
asyncResult.AsyncWaitHandle,
new WaitOrTimerCallback(ScanTimeoutCallback),
requestState,
(TIMEOUT *1000), // obviously because this is in miliseconds
true
);
// Wait until the the call is completed
while (!asyncResult.IsCompleted) { yield return null; }
// Deal up with the results
if (requestState.errorMessage != null) {
if ( requestState.errorMessage.Contains("404") || requestState.errorMessage.Contains("NameResolutionFailure") ) {
result(true);
} else {
Debug.LogWarning("[WebAsync] Error trying to verify if URL '"+ url +"' exists: "+ requestState.errorMessage);
}
}
}
static private void RespCallback (IAsyncResult asyncResult) {
RequestState requestState = (RequestState) asyncResult.AsyncState;
WebRequest webRequest = requestState.webRequest;
try {
webRequest.EndGetResponse(asyncResult);
} catch (WebException webException) {
requestState.errorMessage = webException.Message;
}
}
static private void ScanTimeoutCallback (object state, bool timedOut) {
if (timedOut) {
RequestState requestState = (RequestState)state;
if (requestState != null)
requestState.webRequest.Abort();
} else {
RegisteredWaitHandle registeredWaitHandle = (RegisteredWaitHandle)state;
if (registeredWaitHandle != null)
registeredWaitHandle.Unregister(null);
}
}
}
回答by robert
// javascript in the web player not ios, android or desktop you could just run the following code:
var jscall:String;
jscall="var reqScript = document.createElement('script');";
jscall+="reqScript.src = 'synchmanager_secure2.jsp?userid="+uid+"&token="+access_token+"&rnd='+Math.random()*777;";
jscall+="document.body.appendChild(reqScript);";
Application.ExternalEval(jscall);
// cs
string jscall;
jscall="var reqScript = document.createElement('script');";
jscall+="reqScript.src = 'synchmanager_secure2.jsp?userid="+uid+"&token="+access_token+"&rnd='+Math.random()*777;";
jscall+="document.body.appendChild(reqScript);";
Application.ExternalEval(jscall);
// then update your object using the your return in a function like this
// json return object always asynch
function sendMyReturn(args){
var unity=getUnity();
unity.SendMessage("object", "function", args );
}
sendMyReturn(args);
or you can send it via a AJAX function prewritten custom headers for security purposes with this you would need signed headers and a signed request back from the server I prefer md5 signatures comparatively they are not so big
或者您可以通过 AJAX 函数预先编写的自定义标头出于安全目的发送它,您需要签名的标头和来自服务器的签名请求我更喜欢 md5 签名相对而言它们不是那么大
回答by Danko Kozar
There is a way of doing this asynchronously, without using IEnumerator and yield return stuff. Check out the eDriven framework.
有一种异步执行此操作的方法,而无需使用 IEnumerator 和 yield return 内容。查看 eDriven 框架。
HttpConnector class: https://github.com/dkozar/eDriven/blob/master/eDriven.Networking/Rpc/Core/HttpConnector.cs
HttpConnector 类:https: //github.com/dkozar/eDriven/blob/master/eDriven.Networking/Rpc/Core/HttpConnector.cs
I've been using JsonFX with HttpConnector all the time, for instance in this WebPlayer demo: http://edrivenunity.com/load-images
我一直在使用 JsonFX 和 HttpConnector,例如在这个 WebPlayer 演示中:http://edrivenunity.com/load-images
Not having PUT and DELETE is not a big issue, since all of it could be done using GET and POST. For instance I'm successfully communicating with Drupal CMS using its REST service.
没有 PUT 和 DELETE 不是一个大问题,因为所有这些都可以使用 GET 和 POST 完成。例如,我使用其 REST 服务成功地与 Drupal CMS 通信。

