Search Unity

UnityWebRequest.Post(url, jsonData) sending broken Json

Discussion in 'Multiplayer' started by Olly, Jul 2, 2016.

  1. Olly

    Olly

    Joined:
    Jun 19, 2014
    Posts:
    20
    I'm doing the following: (Don't worry it will be over HTTPS)

    Code (csharp):
    1.  UnityWebRequest.Post(url,jsonData)

    The json data is as follows:
    Code (csharp):
    1.  {"username":"some username","password":"some password"}
    The data is actually of type JsonObject but I've tried passing it as a string too.

    When using PostMan tool in Chrome and sending this data it was processing correctly.

    When sending via Unity I get additional data that fails Json linter:

    Code (csharp):
    1.  { '{"translationKey":"","username":"","password":""}': '' }
    I have tried manually stripping the code; but I'd rather be sending safe json to begin with.

    I'm using Express with NodeJS.

    Can someone tell me what I'm doing wrong?


    ** Edit **

    I'm using JsonUtility.ToJson(jsonData) to parse the data

    Example of Json class:
    Code (csharp):
    1.  
    2. public class JsonObjectNewUser : JsonObjectBase {
    3.  
    4.     public string username;
    5.     public string password;
    6.  
    7.     public JsonObjectNewUser(string username, string password) {
    8.         this.username = username;
    9.         this.password = password;
    10.     }
    11. }
    12.  
    BaseJson
    Code (csharp):
    1.  
    2. [System.Serializable]
    3. publicclassJsonObjectBase{
    4.     publicstringtranslationKey="";
    5. }
    6.  
    Logging JsonUtility.ToJson(jsonObject) produces the correct json:
    Code (csharp):
    1.  
    2. {
    3.     "translationKey": "",
    4.     "username": "",
    5.     "password": ""
    6. }
    7.  
    So something is being added in UnityWebRequest.Post..
     
    Last edited: Jul 2, 2016
  2. Olly

    Olly

    Joined:
    Jun 19, 2014
    Posts:
    20
    I figured this out; use Put request and make sure the content header is set.

    Example
    Code (csharp):
    1.  
    2. var jsonString = JsonUtility.ToJson(jsonData) ?? "";
    3. UnityWebRequest request = UnityWebRequest.Put(url, jsonString);
    4. request.SetRequestHeader("Content-Type", "application/json");
    5. yield return request.Send();
    6.  
     
  3. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    I stumbled upon this same issue. I can't get the POST method to work with JSON, but I can get it to work with PUT.
     
    StoneIron-H-D likes this.
  4. Apparaten_

    Apparaten_

    Joined:
    Jul 9, 2013
    Posts:
    45
    I dont have any trouble with post, what version of unity are you using?

    Im using the wwwform for sending data to server. I only use Jsonutility when i get data from my server.
     
  5. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    I can also use POST with WWWForm. It is using POST where data is JSON formatted and Content-Type is set to application/json.
     
  6. MV10

    MV10

    Joined:
    Nov 6, 2015
    Posts:
    1,889
    UnityWebRequest is a very poor implementation of an HTTP client.

    This might be your problem, depending on what is consuming your request: For some reason UnityWebRequest applies URL encoding to POST message payloads. URL encoding the payload is an ASP.NET webform thing. It is not part of the HTML standard (and if it were, it still shouldn't matter to an HTTP client), and it certainly is not part of the HTTP standard.

    To get an unmangled-POST through, create UnityWebRequest as a PUT, then in your own code change the Method property to POST after the fact.

    Also note that if your RESTful API requires message payloads on GET requests (rare, but it happens, typically as part of sending complex search parameters) you'll either have to change the API or find an alternative to UnityWebRequest. It will simply discard the message body if you change the method to GET. (Note I haven't confirmed it's the GET that discards the body; I also set Content-Type and that may trigger it too, I stopped caring about the specifics after I realized it was blindly throwing away my data.)

    Error handling is also a mess. There is no comprehensive list of the errors the class itself can return and they're just raw text strings. Server response is available strictly as the numeric response status code (annoyingly expressed as longs which means you have to remember to test against "200L" for OK, for example), and UnityWebRequest does not expose the response status description text, which means it throws away potentially useful error messages.

    Oh yeah, it also won't allow an empty message body on a POST or PUT operation, which is also stupid and not to HTTP spec.

    There are open feedback items for most of these. Upvotes would be appreciated. I don't have much hope they'll fix it, though. In another thread a Unity dev started to argue about these, then bailed on the thread entirely. Other threads about these issues have been ignored (or maybe were not noticed in all the other traffic, no way to know for sure).

    Right now I'm pondering whether to break my REST API to accomodate this mess, or ditch UnityWebRequest for some as-yet-unknown alternative, but I need the coroutine/yield async model and I haven't dug into doing that DIY yet. Extremely frustrating.
     
    Last edited: Jul 22, 2016
  7. sandolkakos

    sandolkakos

    Joined:
    Jun 3, 2009
    Posts:
    285
    Today I used that code and now it is working perfectly:

    Code (CSharp):
    1.     IEnumerator Post(string url, string bodyJsonString)
    2.     {
    3.         var request = new UnityWebRequest(url, "POST");
    4.         byte[] bodyRaw = Encoding.UTF8.GetBytes(bodyJsonString);
    5.         request.uploadHandler = (UploadHandler) new UploadHandlerRaw(bodyRaw);
    6.         request.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer();
    7.         request.SetRequestHeader("Content-Type", "application/json");
    8.  
    9.         yield return request.Send();
    10.  
    11.         Debug.Log("Status Code: " + request.responseCode);
    12.     }
    Source: http://qiita.com/mattak@github/items/d01926bc57f8ab1f569a

    Edit (2020):
    It has already some time I don't use the POST method in my projects, but I know that Unity changed a little bit the UnityWebRequest and added a new method only for Post. Here you are the Documentation about it:
    https://docs.unity3d.com/ScriptReference/Networking.UnityWebRequest.Post.html
     
    Last edited: Nov 23, 2020
  8. Freaking-Pingo

    Freaking-Pingo

    Joined:
    Aug 1, 2012
    Posts:
    310
    I am currently using UnityWebRequest for our REST api, and I find it easy to use, and haven't stumbled upon that many issues. Could you pleas link to the open feedback requests?
     
  9. elpuerco63

    elpuerco63

    Joined:
    Jun 26, 2014
    Posts:
    271
    I am using UnityWebRequest example from here: https://docs.unity3d.com/Manual/UnityWebRequest-SendingForm.html
    using our https url and although I get upload completed there server receives nothing.

    I also note from that site that webform is legacy and UnityWebRequest is the 'new' way of doing it...but not if it does not work?
     
  10. sandolkakos

    sandolkakos

    Joined:
    Jun 3, 2009
    Posts:
    285
    @elpuerco63,
    Have you tried use this?
     
    rvejendla, RadianSmile and fangyan67 like this.
  11. elpuerco63

    elpuerco63

    Joined:
    Jun 26, 2014
    Posts:
    271
  12. sandolkakos

    sandolkakos

    Joined:
    Jun 3, 2009
    Posts:
    285
  13. MrSaoish

    MrSaoish

    Joined:
    Oct 1, 2016
    Posts:
    22
    I believe it required a php on http server in order to use UnityWebRequest.Post() or UnityWebRequest.Put successfully?
    I'm trying to use UnityWebRequest.Put to upload player data in jason to http server and overwrite its .txt but I'm very new to this category and having 0 experience on php scripting, does anyone have some reference .php codes I could learned from?
     
  14. sandolkakos

    sandolkakos

    Joined:
    Jun 3, 2009
    Posts:
    285
    First of all, you need to learn how to code a "PHP Rest API" system that will receive data as Json and later manage the data to write in your .txt file. But maybe it will be better if instead of a .txt file, you save the data in a MySQL database.

    Just search for "PHP Rest API" tutorials and you will learn it after some time of study.

    You can use a good tool to test your PHP system before code in Unity:
    https://www.getpostman.com/apps

    After your PHP system is done, you can go to Unity and implement your "UnityWebRequest.Post".
     
    petrapparent likes this.
  15. JanouschScanblue

    JanouschScanblue

    Joined:
    May 31, 2017
    Posts:
    1
    Worked like a charm for me.
    This is how my JsonString looked like:
    "{
    'email': '*****@test.de',

    'password': '*****'
    }"
     
  16. disny1234

    disny1234

    Joined:
    Sep 21, 2014
    Posts:
    23
    I want to send some video data to servers and want to show upload progress in android using unity web request
    This html code is working, URL is working, please give me some example to achieve in unity android

    <html>
    <body>
    <form method="post" action="http://139.59.20.91/uploadVideos.php" enctype="multipart/form-data">

    Video : <input type="file" name="course_video"><br>
    <br>

    <input type="submit" value="Submit"><br>
    </form>
    </body>
    </html>
     
  17. heru_

    heru_

    Joined:
    Jun 7, 2017
    Posts:
    2
    Thanks, you've save my time
     
  18. timmehhhhhhh

    timmehhhhhhh

    Joined:
    Sep 10, 2013
    Posts:
    157
    this should be starred / stickied / favorited everywhere - headache cured. will keep the other bits of your reply in mind as well, cheers!
     
  19. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    The other alternative is to manually encode your JSON string to byte array and feed that.
     
  20. Finer_Games

    Finer_Games

    Joined:
    Nov 21, 2014
    Posts:
    33
    Would there be a way to make this work, if we needed to provide image data as a base64 string?
     
  21. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    The UploadHandlerBuffer takes byte array and send it as is. When using higher level functions byte array is passed directly to UploadHandlerBuffer, while anything else is transformed into byte array.
    So, if you need to send data encoded in specific form, encode it yourself and produce byte array.
     
  22. scarffy

    scarffy

    Joined:
    Jan 15, 2013
    Posts:
    25
    Is there anyway to set multiple headers using SetRequestHeaders ?
    I need to give ("Content-Type", "application/json") and ("Authorization", token). I've been searching and trying for hours but I can't find a way to do it using UnityWebRequest
     
  23. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    If keys are different, call SetRequestHeader() multiple times.
    I think what you can't do is have multiple headers with the same key, but in such cases you should be able to have only one header and put different values using comma as a separator.
     
  24. scarffy

    scarffy

    Joined:
    Jan 15, 2013
    Posts:
    25
    Using the this example code, do I code like this?

    1. IEnumerator Post(string url, string bodyJsonString)
    2. {
    3. var request = new UnityWebRequest(url, "POST");
    4. byte[] bodyRaw = Encoding.UTF8.GetBytes(bodyJsonString);
    5. request.uploadHandler = (UploadHandler) new UploadHandlerRaw(bodyRaw);
    6. request.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer();
    7. request.SetRequestHeader("Content-Type", "application/json");
    8. request.SetRequestHeader("Authorization", "my_token");
    1. yield return request.Send();

    2. Debug.Log("Status Code: " + request.responseCode);
    3. }
     
  25. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    Yes. The casts in lines 5 and 6 are redundant, but not an error. And I recommend checking request.isError after request is completed.
     
    Sami_AlEsh likes this.
  26. scarffy

    scarffy

    Joined:
    Jan 15, 2013
    Posts:
    25
    I see.Thank you!
    Then if I have more headers, I'll just add request.SetHeader more right?
     
  27. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    Yes, you can add as many headers as you want. Only I think it will replace header if you add the second header with the same key.
     
  28. arufolo

    arufolo

    Joined:
    Mar 5, 2013
    Posts:
    8
    You're a life saver man!!!

    www = UnityWebRequest.Put(url, bodyJSON);
    www.method = "POST";

    This was the only way I could get a POST request to work with a JSON body.
    Really poorly implemented HTTP Client on Unity's part.
     
  29. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    You use it not the way it is designed to be used.
    UnityWebRequest.Post(string, string) assumes HTTP form for second argument. If you want to send it raw, encode it to bytes (Encoding.UTF8.GetBytes(string), this is what Put does under the hood) and use UnityWebRequest.Post(string, byte[]).
     
  30. AMNOD

    AMNOD

    Joined:
    Oct 19, 2014
    Posts:
    13
    Thanks A LOTTTTT !!!
     
    JesOb and marllon_alfaebeto like this.
  31. Saulius

    Saulius

    Joined:
    Aug 10, 2010
    Posts:
    21
    I had similar problem. Everything worked on local xampp server and some other free hosting server. But when I use paid hosting I began to get empty body values. Nothing helped until I installed Wireshark and compared request sent from POSTMAN and Unity, and found out that unity had chunked transfer on by default and that web server didn't liked that for some reason.
    So setting webRequest.chunkedTransfer = false; solved it. Just in case someone will have such a problem, give a try to this solution.
     
    JesOb, xlabrom, jvalencia and 2 others like this.
  32. raincrowgames

    raincrowgames

    Joined:
    Jul 17, 2015
    Posts:
    1
    I know this is an old post but THANK YOU! you are lifesaver!
     
  33. scarffy

    scarffy

    Joined:
    Jan 15, 2013
    Posts:
    25
    This code works great but for some reason it didn't work with Hololens. It give me "Generic/Unknown Http error"
     
  34. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    This error means that communication with the server was successful, but server responded with HTTP error. The isHttpError property should be true on UnityWebRequest and responseCode should give the exact cause.
    One common reason for this to happen is when server does not support chunked transfer, which is what UnityWebRequest uses by default. Try setting chunkedTransfer property to false.
     
  35. scarffy

    scarffy

    Joined:
    Jan 15, 2013
    Posts:
    25
    I tested it. It didn't work but shouldn't it respond me with that error while I'm in editor mode and also in Hololens?
    Currently, I only receive this error only when I deploy to Hololens but not in editor.
     
  36. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    The response should be the same for the identical request. Different response indicates that the request was somehow different. Check the response code, that can give some clue in what way it was different.
     
  37. scarffy

    scarffy

    Joined:
    Jan 15, 2013
    Posts:
    25
    This is kinda weird. In unity editor it give me 200 but in hololens it give me 500.
     
  38. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    You need to looks at network traffic then to see what data is being transmitted.
     
  39. scarffy

    scarffy

    Joined:
    Jan 15, 2013
    Posts:
    25
    I looked at network traffic and what data is being transmitted. It seems like JsonUtility doesn't work in Hololens for some reason. I'm using newtonsoft.Json and just like that, it's working fine. Thanks @Aurimas-Cernius for the direction you gave me.
     
    Last edited: Jan 19, 2018
  40. Kraato5

    Kraato5

    Joined:
    Mar 11, 2015
    Posts:
    2
    God bless you, mate! God bless you!
     
    jvalencia likes this.
  41. fangyan67

    fangyan67

    Joined:
    Feb 25, 2014
    Posts:
    4
    Thank you thank you, It's so useful.
     
  42. Romaleks360

    Romaleks360

    Joined:
    Sep 9, 2017
    Posts:
    72
    How's that possible if UnityWebRequest.Post(string, string) accepts only strings as arguments?
     
  43. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    There are multiple overloads of this methods accepting different arguments.
     
  44. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    There is no overload of UnityWebRequest.Post(String, Byte[]) so writing all this by hand is the only option
     
    JoeStrout likes this.
  45. ismaelnascimentoash

    ismaelnascimentoash

    Joined:
    Apr 2, 2017
    Posts:
    30
    Very good ! Works for me !
     
    seanNovak and sandolkakos like this.
  46. sconi

    sconi

    Joined:
    May 15, 2017
    Posts:
    1
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using LitJson;
    5. using System.Text;
    6. using System;
    7. using System.Net;
    8. using UnityEngine.Networking;
    9.  
    10. public class BL_Online_PicBook : MonoBehaviour {
    11.     public string tokenBulu;
    12.     private string path = "http://localhost:8080";
    13.     // Use this for initialization
    14.     void Start ()
    15.     {
    16.         StartCoroutine(GetPicBook());
    17.     }
    18.  
    19.     // Update is called once per frame
    20.     void Update () {
    21.      
    22.     }
    23.  
    24.     IEnumerator GetPicBook()
    25.     {
    26.         var request = new UnityWebRequest(path, "POST");
    27.         JsonData str = new JsonData();
    28.         str["pageNumber"] = 0;
    29.         string jsonStr = str.ToJson();
    30.         byte[] bodyRaw = Encoding.UTF8.GetBytes(jsonStr);
    31.         request.uploadHandler = new UploadHandlerRaw(bodyRaw);
    32.         string getByte = Encoding.ASCII.GetString(bodyRaw);
    33.         Debug.Log(getByte);
    34.         request.downloadHandler = new DownloadHandlerBuffer();
    35.         request.SetRequestHeader("Authorization", tokenBulu);
    36.         request.SetRequestHeader("Content-Type", "application/json");
    37.         yield return request.SendWebRequest();
    38.         Debug.Log("Status Code:" + request.downloadHandler.text);
    39.        
    40.     }
    41.  
    42. }
    43.  
    JSON conversion is required when passing values!
     
  47. 3pns

    3pns

    Joined:
    Sep 5, 2014
    Posts:
    4
    After more than 1 day of trouble was able to query my RESTfull json api with Newtonsoft.Json library to parse Hashtables and your snippet to properly encode the request. Thank you very much !
    As others have said this is a terrible implementation of a http client and doesn't follow web standards, it should be sending raw request by default and thus only adding the "application/json" header should be needed. That's the least you can expect from a http client library in 2019.
    At the very least It would be great if how to make Json request using UnityWebRequest was documented in the official documentation.
     
    Last edited: May 10, 2019
    median likes this.
  48. Sir-Gatlin

    Sir-Gatlin

    Joined:
    Jan 18, 2013
    Posts:
    28
    since .Send is now deprecated you have to change it to this
    Code (CSharp):
    1. IEnumerator Post(string url, string bodyJsonString)
    2.     {
    3.         var request = new UnityWebRequest(url, "POST");
    4.         byte[] bodyRaw = Encoding.UTF8.GetBytes(bodyJsonString);
    5.         request.uploadHandler = (UploadHandler) new UploadHandlerRaw(bodyRaw);
    6.         request.downloadHandler = (DownloadHandler) new DownloadHandlerBuffer();
    7.         request.SetRequestHeader("Content-Type", "application/json");
    8.         yield return request.SendWebRequest();
    9.         Debug.Log("Status Code: " + request.responseCode);
    10.     }
     
    Evercloud, JoRangers and JohnTube like this.
  49. stickylab

    stickylab

    Joined:
    Mar 16, 2016
    Posts:
    92
    i dont know how to do at all
     
  50. PHL1

    PHL1

    Joined:
    Jul 25, 2017
    Posts:
    29
    thank you very very much man
     
    sandolkakos likes this.