- Home /
Can you post a json string as a body in Unity?
I'm trying to post a json string as the body of a UnityWebRequest but it just fails throws protocolerror and doesnt work.
I can post using postman.
I can get data using pretty much the exact same function except for a few changes.
Post just isnt working for me.
public static async Task<string> PostData(string url, string data)
{
using(UnityWebRequest request = UnityWebRequest.Post(url, data))
{
request.SetRequestHeader("Content-Type", "application/json");
request.SetRequestHeader("Accept", "application/json");
var operation = request.SendWebRequest();
while(!operation.isDone)
{
await Task.Yield();
Debug.Log($"({request.downloadProgress}%)");
}
if(request.isHttpError || request.isNetworkError)
{
Debug.Log("Request failed...");
return null;
}
if(request.result == UnityWebRequest.Result.Success)
return request.downloadHandler.text;
return null;
}
}
Answer by Yoconn · Oct 02, 2021 at 05:47 AM
hmm, my body was coming in as something like Text.File.Json or something similar. So my asp.net app was looking for a string
PostFunction([FromBody]string data)
But Unity, or my code dunno, was sending it as the Text.File.Json or whichever it was. So I changed my code to
PostFunction([FromBody]object data)
Which, when debugging it locally, caused it to actually hit my breakpoint and start the function.
Hope this helps anybody else trying to Post to an asp.net web api. Goodluck
Answer by Bunny83 · Sep 29, 2021 at 12:13 AM
Well, this is a common pitfall with Unity's Post method. For some reason they throught it's a great idea that by default any Post request will send url encoded data which is extremely unintuitive. See the exact implementation here.
If you want to post raw text / json / binary / whatever you have to provide your own UploadHandlerRaw and provide your data that way.
I quickly setup a php script like this:
<?php
$postData = file_get_contents("php://input");
$request = json_decode($postData, true);
$request["result"] = "FooBar";
$result = json_encode($request, JSON_PRETTY_PRINT);
header("Content-Type", "application/json");
echo $result;
?>
and added this line before your SendRequest line:
request.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(data));
This will replace the upload handler with our own and we simply perform an UTF8 encoding on the text.
I used my SimpleJSON (since I already had it in my project) just to run this example:
async void Start()
{
JSONNode n = new JSONObject();
n["test"] = 42;
Debug.Log("Request: " + n.ToString(3));
string res = await PostData("MyURL/php/JsonTest.php", n.ToString());
var node = JSON.Parse(res);
Debug.Log("Response: " + node.ToString(3));
}
So the php script will parse the json into an object, add a new field called "result" and simply return whatever was send in to the client. The two log statements in Unity look like this:
Request: {
"test" : 42
}
Response: {
"test" : 42,
"result" : "FooBar"
}
So this works as expected once you use a raw upload handler.
Hmm, i tried what you suggested and im getting this as an error now HTTP/1.1 400 Bad Request
Do you know if my web service only allowing https would cause an error?
My request was an https request onto my raspberry pi server which runs an apache server with a lets encrypt wildcard certificate on my own dyn dns domain. So, it does work with https ^^. When you get a 400 Bad Request the error may be on your server side. I don't know what you run as server or what that service may expect. Are you even sure that the json you post from Unity is valid json?
Since it's difficult to use WireShark when you use https, if you can temporarily switch to http, you could use it to inspect the packets that actually go out. Another option which is a bit simpler is to create a WebGL build and use the web developer tools in firefox or chrome to inspect the request there in the network tab. Though running a webgl build locally has lots of other issues. The most robust solution is when you can host it on an actual web server. You could use something like XAMPP or similar package. Or use something like github pages to host your build. Of course your API (which probably runs on a different server / domain) has to use CORS in order to allow cross domain access. Again we don't know anything about the service you're using. Is this your own server you have setup? Or is it some kind of backend you have no control over?
Hmm, I've tried running it locally as well and changing my IP to a localhost and setting a breakpoint on the function and it doesn't even hit it.
My service is a .net core web API running on a Linux server I pay for through DigitalOcean. So I pretty much control everything, I'm also using letsencrypt.
Its successful if I run my local build using swagger and it can pull/push data to the server. I can also post/get using postman. It all works except for inside Unity for whatever reason.
I'm still somewhat new to netcore web API, but I wonder if since it's expecting a string as the body and since Unity puts a byte[] in the body (or am I mistaken?) that I have to update the service to look for a byte[]. I didn't think it would skip over my breakpoint entirely but it might. (Once upon a time I tried PHP but it drove me mad and I hopped ship to netcore)
I'll have to look into this when I get home from work today.
I also deeply appreciate you having a back and forth with me. Normally I get an initial comment and no follow up ones. <3 Cheers
Your answer
Follow this Question
Related Questions
Webrequest Post SetRequestHeader Problem 0 Answers
Posting JSON-RPC with WebRequest 0 Answers
Can't Send a form to a server(POST) due to CORS error in a WEBGL build 1 Answer
How do I parse JSON from an API and import the variables into a gameobject component during runtime? 0 Answers
Pass Headers and Arguments in UnityWebRequest POST Method Object 1 Answer