简体   繁体   中英

Unity - How to use a Dictionary of parameters instead of a String with HttpWebRequest

I'm not so experienced with C#, anyway I'm using the following function to post data to my own API:

public static JSONNode SaveObject(List<String> parameters){
  var request = (HttpWebRequest)WebRequest.Create("http://example.com/query.php?");
  var data = Encoding.ASCII.GetBytes(String.Join("",parameters));
  request.Method = "POST";
  request.ContentType = "application/x-www-form-urlencoded";
  request.ContentLength = data.Length;
  using (var stream = request.GetRequestStream()){ stream.Write(data, 0, data.Length); }
  var response = (HttpWebResponse)request.GetResponse();
  var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
        
  // Debug.Log("RESPONSE: " + responseString);
        
  // JSONNode object
  var obj = JSON.Parse(responseString);
                
  return obj;
}

Here's how I call it:

List<String> parameters = new List<String>();
parameters.Add("tableName=Posts"));
parameters.Add("&text=Text & more"));
parameters.Add("&number=123"));
// Save
var result = SaveObject(parameters);
Debug.Log("OBJECT SAVED: " + result.ToString());

I was fine with my SaveObject() function until I've found out that the Text & more String gets truncated to Text in my JSON file to the "text" key (my API simply edits JSON files).

I know why that happens, it's because the String.Join("",parameters) generates a URL string that looks like "tableName=Posts&text=Text & more&number=123" , so the & character between Text and more gets invalidated because my PHP code thinks it's a separator like the other & 's

So I can't figure out how to transform my SaveObject() function to use a Dictionary of parameters instead of a String. If I'll use something like a <string, string> dictionary, I think I'll solve my & character issue, nice Iìm using a Dictionary for the iOS code that calls my API

You should rather use a UnityWebRequest.Post the 4th overload is

public static Networking.UnityWebRequest Post(string uri, Dictionary<string,string> formFields); 

and does exactly what you are trying I guess.

The Content-Type header will be set to application/x-www-form-urlencoded.

So you don't even have to do that manually.

You would need a reference to a MonoBehaviour though in order to run a Coroutine and wait for the result as otherwise you would block the Unity main thread:

public static void SaveObject(MonoBehaviour behaviour, Dictionary<string, string> parameters, Action<JSONNode> resultHandler)
{
    behaviour.StartCoroutine(SendSaveRequest(parameters, resultHandler));
}

private static IEnumerator SendSaveRequest(Dictionary<string, string> parameters, Action<JSONNode> resultHandler)
{
    using(var uwr = UnityWebRequest.Post("http://example.com/query.php?", parameters)
    {
        yield return uwr.SendWebRequest();

        if (uwr.isNetworkError || www.isHttpError)
        {
            Debug.Log(www.error);
        }
        else
        {
            Debug.Log("Form upload complete!");

            var responseString = uwr.downloadHandler.text;
        
            // Debug.Log("RESPONSE: " + responseString);
        
            // JSONNode object
            var obj = JSON.Parse(responseString);
                
            resultHandler?.Invoke(obj);
        }
    }
}

So you would call it like (assuming this code is in a MonoBehaviour script)

var parameters = new Dictioary<string,string>
{
    {"tableName","Posts"},
    {"text","Text & more"},
    {"number","123"}
};

// Save
var result = SaveObject(this, parameters, OnSaveDone);

...

private void OnSaveDone(JSONNode result)
{
    Debug.Log("OBJECT SAVED: " + result.ToString());
}

Alternatively you could of course simply do something like

var data = Encoding.ASCII.GetBytes(String.Join("",parameters));
data = data.Replace(" ", "_SPACE_").Replace("&", "_AND_");

an then on the PHP receiver side replace the other way round before handling the parameters (of course more error prone)

$search = array("_SPACE_","_AND_");
$replace = array(" ", "&");

$escapedValue = $_POST["parameter"];
$value = str_replace($search, $replace, $escapedValue);

Note: Typed on smartphone but I hope the idea gets clear

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM