20

JSONを送受信するには、すべての標準的なRESTfulメソッドを使用してHTTPリクエストを送信し、リクエストの本文にアクセスする必要があります。調べてみた

WebRequest.HttpWebRequest

これはほぼ完全に機能しますが、たとえば、サーバーがダウンしている場合、関数GetResponseが戻るのに数秒かかる場合があります-同期メソッドであるため-その期間、アプリケーションをフリーズします。このメソッドの非同期バージョンであるBeginGetResponseは、その期間中もアプリケーションをフリーズするため、(とにかくUnityでは)非同期的に機能していないようです。

UnityEngine.WWW#

何らかの理由でPOSTおよびGETリクエストのみをサポートしますが、PUTおよびDELETE(標準のRESTfulメソッド)も必要なので、これ以上調べる必要はありませんでした。

System.Threading

アプリケーションをフリーズせずにWebRequest.HttpWebRequest.GetResponseを実行するために、スレッドを使用して調べました。スレッドはエディターで機能しているように見えます(ただし、非常に不安定なようです。アプリケーションの終了時にスレッドを停止しないと、停止してもエディターで実行され続けます)。iOSデバイスにビルドすると、すぐにクラッシュします。スレッドを開始しようとしています(エラーを書き留めるのを忘れたため、現在アクセスできません)。

Unityアプリへのブリッジを備えたネイティブiOSアプリでスレッドを実行する

ばかげている、これを試みるつもりさえない。

UniWeb

これ。彼らがどうやってそれを管理したのか知りたいです。

これが私が試している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

4

4 に答える 4

10

さて、私はついに自分のソリューションを書くことができました。基本的に、RequestStateCallbackメソッド、およびTimeOutスレッドが必要です。ここでは、UnifyCommunity(現在はunity3d wikiと呼ばれています)で行われたことをコピーします。これは古いコードですが、そこにあるものよりも小さいので、ここに何かを表示する方が便利です。今、私は(unit3d wikiで)削除しSystem.Actionstaticパフォーマンスと単純さのために:

使用法

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

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);
        }
    }
}
于 2012-09-26T17:11:11.427 に答える
1

iOSでスレッドを動作させるようになりました-ゴーストスレッドなどが原因でクラッシュしていたと思います。デバイスを再起動するとクラッシュが修正されたようですので、スレッドでWebRequest.HttpWebRequestを使用します。

于 2012-09-04T17:18:13.687 に答える
-1

IEnumeratorとyieldreturnを使用せずに、これを非同期で行う方法があります。eDrivenフレームワークを確認してください。

HttpConnectorクラス:https ://github.com/dkozar/eDriven/blob/master/eDriven.Networking/Rpc/Core/HttpConnector.cs

私はいつもHttpConnectorでJsonFXを使用しています。たとえば、次のWebPlayerデモでは次のようになります。http://edrivenunity.com/load-images

PUTとDELETEがないことは大きな問題ではありません。これは、すべてGETとPOSTを使用して実行できるためです。たとえば、RESTサービスを使用してDrupalCMSと正常に通信しています。

于 2013-02-02T20:33:56.330 に答える
-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関数で事前に作成されたカスタムヘッダーを介して送信することもできます。これには、署名されたヘッダーとサーバーからの署名されたリクエストが必要です。

于 2012-11-30T22:25:06.340 に答える