我需要使用所有标准RESTful方法发送HTTP请求,并访问请求正文以便使用它发送/接收JSON。我已经调查过,
这几乎完美无缺,但有些情况下,例如,如果服务器关闭,则函数GetResponse可能需要几秒钟才能返回 - 因为它是一种同步方法 - 冻结该时段的应用程序。这个方法的异步版本,BeginGetResponse,似乎不是异步工作(在Unity中),因为它仍然冻结该时期的应用程序。
由于某种原因仅支持POST和GET请求 - 但我还需要PUT和DELETE(标准RESTful方法),所以我没有进一步深入研究它。
为了运行WebRequest.HttpWebRequest.GetResponse而不冻结应用程序,我研究了使用线程。线程似乎在编辑器中工作(但看起来非常不稳定 - 如果您在应用程序退出时不停止某个线程,即使您停止它也会永远在编辑器中运行),并且当构建到iOS设备时它会崩溃一旦我尝试开始一个帖子(我忘记写下错误,我现在无法访问它)。
荒谬,甚至不打算尝试这个。
此。我想知道他们是如何管理它的。
以下是我正在尝试的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);
}
}
......基于此:http://msdn.microsoft.com/en-us/library/86wf6409(v=vs.71).aspx
答案 0 :(得分:9)
好的,我终于设法写了my own solution。我们基本上需要 RequestState ,回调方法和 TimeOut线程。在这里,我将复制what was done in UnifyCommunity(现在称为unity3d wiki)。这是过时的代码,但比那里的更小,所以更方便在这里展示一些东西。现在我删除了(在unit3d wiki中)System.Action
和static
以获得性能和简单性:
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);
}
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);
}
}
}
答案 1 :(得分:1)
我有线程在iOS上工作 - 我相信它因为鬼线或其他东西而崩溃。重新启动设备似乎修复了崩溃,所以我只使用带有线程的WebRequest.HttpWebRequest。
答案 2 :(得分:-1)
// 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);
或者为了安全起见,您可以通过AJAX函数预先编写的自定义标头发送它 有了这个,您需要从服务器返回已签名的标头和已签名的请求 我比较喜欢md5签名他们不是那么大
答案 3 :(得分:-1)
有一种方法可以异步执行此操作,而无需使用IEnumerator和yield return东西。查看eDriven框架。
HttpConnector类:https://github.com/dkozar/eDriven/blob/master/eDriven.Networking/Rpc/Core/HttpConnector.cs
我一直在使用JsonFX和HttpConnector,例如在这个WebPlayer演示中:http://edrivenunity.com/load-images
没有PUT和DELETE不是一个大问题,因为所有这些都可以使用GET和POST完成。例如,我使用其REST服务与Drupal CMS成功通信。