UnityWebRequest not sending POST data - c#

When Unity sends the POST request it doesn't pass the POST data, so the server returns an error (it gets the server response). I've seen that several people had a similar issue and it got fixed by adding www.chunkedTransfer = false;, however, that doesn't work for me.
I've also seen that some people use WWWForm instead of IMultipartFormSection, but I haven't tried it because it is deprecated.
I'm using PHP, but I've also tried it with Perl and it didn't work either. When I manually send a POST request everything works normally, so it seems the issue is in Unity. I'm new to Unity, so any help would be appreciated. I'm using the current latest version, 2018.2.18f1 Personal.
My code is pretty much the same as the official Unity documentation for sending POST request, but apparently it doesn't work. Here is my code:
C#:
public void Click() {
StartCoroutine(PostRequest("http://127.0.0.1/test.php", "help"));
}
IEnumerator PostRequest(string url, string data) {
List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
formData.Add(new MultipartFormDataSection("data=" + data));
UnityWebRequest www = UnityWebRequest.Post(url, formData);
www.chunkedTransfer = false;
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError) {
Debug.Log(www.error);
} else {
Debug.Log(www.downloadHandler.text);
}
}
PHP:
<?php echo "Server received: " . $_POST["data"]; ?>

Christoph Lütjen pointed out that according to this it should be new MultipartFormDataSection("data", data), despite the official documentation example using new MultipartFormDataSection("field1=foo&field2=bar").
Changing it to new MultipartFormDataSection("data", data) fixed the issue.

Related

How to update user picture using PUT method in Unity3D

I'm a beginner in Unity3D; i have to develop a mobile app and i need to manage user profile data; i have to communicate these data with server using REST services.
Everything works fine when i send Json (eg name, email, phone number, etc.) from my app, but I can't update the profile picture.
What i need is:
Content-Type = multipart/form-data
key="profile_picture", value=file_to_upload (not the path)
I read a lot about networking in Unity and tried different combinations of UnityWebRequest, List, WWWform but nothing seems to work for this kind of PUT service.
UnityWebRequest www = new UnityWebRequest(URL + user.email, "PUT");
www.SetRequestHeader("Content-Type", "multipart/form-data");
www.SetRequestHeader("AUTHORIZATION", authorization);
//i think here i'm missing the correct way to set up the content
I can correctly simulate the update from Postman, so it's not a problem with server; i'm pretty sure that the problem is that i can't convert this logic inside the app.
Upload from Postman correctly working(1)
Upload from Postman correctly working(2)
Any kind of help and code suggestion will be appreciated.
Thanks
With Put you usually only send file data but without a form.
You can add a multipart form using UnityWebRequest.Post
IEnumerator Upload()
{
List<IMultipartFormSection> formData = new List<IMultipartFormSection>();
formData.Add(new MultipartFormFileSection("profile_picture", byte[], "example.png", "image/png"));
UnityWebRequest www = UnityWebRequest.Post(url, formData);
// change the method name
www.method = "PUT";
yield return www.SendWebRequest();
if(www.error)
{
Debug.Log(www.error);
}
else
{
Debug.Log("Form upload complete!");
}
}
using a MultipartFormFileSection
Or alternatively you can use a WWWForm
IEnumerator Upload()
{
WWWForm form = new WWWForm();
form.AddBinaryData("profile_picture", bytes, "filename.png", "image/png");
// Upload via post request
var www = UnityWebRequest.Post(screenShotURL, form);
// change the method name
www.method = "PUT";
yield return www.SendWebRequest();
if (www.error)
{
Debug.Log(www.error);
}
else
{
Debug.Log("Finished Uploading Screenshot");
}
}
using WWWForm.AddBinaryData
Note that for user authentication you have to encode your credentials properly:
string authenticate(string username, string password)
{
string auth = username + ":" + password;
auth = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(auth));
auth = "Basic " + auth;
return auth;
}
www.SetRequestHeader("AUTHORIZATION", authenticate("user", "password"));
(Source)

Get reply from remote server using C# and PHP

I'm trying to get data from a remote server using C#. I tried using a simple script to see if "it works", but I'm not getting a response. The same script works on a local server, so I'd like to know how I can do it.
This is my C# code:
IEnumerator Sayhi()
{
WWWForm sendInfo = new WWWForm();
sendInfo.AddField("function", function);
WWW www = new WWW(bl_LoginDataBase.Instance.GetUrl(bl_LoginDataBase.URLType.CallFunction), sendInfo);
yield return www;
Debug.Log(www.text);
}
And the PHP code:
<?php
echo "Hi";
I expected the Debug.Log(www.text); to print Hi, which it does if I use a local machine (http://192.168.0.whatever), but the remote server (http://whatever.example.com) doesn't return anything. I tried making the php fail so it returns an error, make a database and return some values from there, but nothing. I'd like to point out it does work on a local server, and works as intended.
What am I doing wrong?
Edit: By the way, if I access http://www.whatever.example.com/Function.php via browser, it shows the echo result.
C# has built in classes and methods to help you perform such tasks.You can use the WebClient class to connect to web servers (using GET or POST) and even send form values to it easily. See below:
string url ="http://www.whatever.example.com/Function.php";
var reqparam = new System.Collections.Specialized.NameValueCollection();
reqparam.Add("name", "John Doe");
try
{
using (System.Net.WebClient client = new System.Net.WebClient())
{
byte[] responsebytes = client.UploadValues(url, "POST", parameters);
string output = System.Text.Encoding.UTF8.GetString(responsebytes);
}
}
catch (Exception x)
{
//an error occured
}
The variable output will contain the response you want "Hi".

Send POST request with Image from Unity3D

I'm trying to send an image to my NodeJS API from Unity but unfortunately I can't make it work. Here is an extract of my c# code:
private string POSTUrl = "http://myNodeJSAPI.com/upload-image";
private Dictionary<string, string> postHeader = new Dictionary<string, string>();
public WWW POST() {
WWW www;
postHeader["content-Type"] = "application/octet-stream";
postData = File.ReadAllBytes("Assets/Resources/ImageIWantToSend.png");
www = new WWW(POSTUrl, postData, postHeader);
StartCoroutine(WaitForRequest(www));
return www;
}
IEnumerator WaitForRequest(WWW www)
{
yield return www;
if (www.error == null)
{
Debug.Log("WWW Ok!: " + www.text);
}
else
{
Debug.Log("WWW Error: " + www.error);
}
}
and here the relevant part of my nodejs one:
app.post('/upload-image', rawBody, function (req, res) {
console.log("File received!");
if (req.rawBody && req.bodyLength > 0) {
fs.writeFile("/tmp/ImageIWantToSend.png", req.rawBody, function (err) {
if (err) {
return console.log(err);
}
console.log("Image has been saved! Starting other things...");
})
}
}
The request is sent but never received by the API (I get 503 bad gateway). I try the same request outside Unity and it seems to work (using Postman: basic post request with image attached as binary).
Did I make a mistake, or is there another way to achieve this?
Thanks!
EDIT: I finally solved the problem by changing application/octet-stream to text/html. If there is a better way to send data to Nodejs I'm still interested
Check out Unity's new UnityWebRequest class.It is a replacement for original WWW.
You can also use C# WebClient or HttpWebRequest class. They work with Unity if you are not using WebGL build.
This is also a good unity plugin to handle requests, though it is not free.

Differences between using C# HttpClient API and the postman testing? Client call works on postman, but not C# httpClient getAsync

I am testing a REST API post, and it works well when I try it on Postman. However, in some scenario (related to the posting XML data) if I post with HttpClient API, I would receive the following error:
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
But the same XML content works fine on Postman with status OK and proper response.
What is the differences between using the C# HttpClient API and the postman testing? How can I configure my API call to match with the behavior on postman?
Here I attached the source code, and the Postman screenshot
public void createLoan()
{
string baseCreateLoanUrl = #"https://serverhost/create?key=";
var strUCDExport = XDocument.Load(#"C:\CreateLoan_testcase.xml");
using (var client = new HttpClient())
{
var content = new StringContent(strUCDExport.ToString(), Encoding.UTF8, Mediatype);
string createLoanApi = string.Concat(baseCreateLoanUrl, APIKey);
try
{
var response = client.PostAsync(createLoanApi, content).Result;
}
catch (Exception ex)
{
MessageBox.Show("Error Happened here...");
throw;
}
if (response.IsSuccessStatusCode)
{
// Access variables from the returned JSON object
string responseString = response.Content.ReadAsStringAsync().Result;
JObject jObj = JObject.Parse(responseString);
if (jObj.SelectToken("failure") == null)
{
// First get the authToken
string LoanID = jObj["loanStatus"]["id"].ToString();
MessageBox.Show("Loan ID: " + LoanID);
}
else
{
string getTokenErrorMsg = string.Empty;
JArray errorOjbs = (JArray) jObj["failure"]["errors"];
foreach (var errorObj in errorOjbs)
{
getTokenErrorMsg += errorObj["message"].ToString() + Environment.NewLine;
}
getTokenErrorMsg.Dump();
}
}
}
Thanks for Nard's comment, after comparing the header, I found the issue my client header has this:
Expect: 100-continue
While postman doesn't has.
Once I removed this by using the ServicePointManager:
ServicePointManager.Expect100Continue = false;
Everything seems fine now. Thanks all the input!
My gut tells me it's something simple. First, we know the API works, so I'm thinking it's down to how you are using the HttpClient.
First things first, try as suggested by this SO answer, creating it as a singleton and drop the using statement altogether since the consensus is that HttpClient doesn't need to be disposed:
private static readonly HttpClient HttpClient = new HttpClient();
I would think it would be either there or an issue with your content encoding line that is causing issues with the API. Is there something you are missing that it doesn't like, I bet there is a difference in the requests in Postman vs here. Maybe try sending it as JSON ala:
var json = JsonConvert.SerializeObject(strUCDExport.ToString());
var content = new StringContent(json, Encoding.UTF8, Mediatype);
Maybe the header from Postman vs yours will show something missing, I think the real answer will be there. Have fiddler running in the background, send it via Postman, check it, then run your code and recheck. Pay close attention to all the attribute tags on the header from Postman, the API works so something is missing. Fiddler will tell you.
I was struggling with this for 2 days when I stumbled over Fiddler which lets you record the traffic to the service. After comparing the calls I saw that I had missed a header in my code.

Send XML to RESTful web service from Unity

I'm using WWW to interact with a RESTful web service. I have a problem sending XML files to the server through POST requests, though. This is my code:
if(Syste.IO.File.Exists(filePath)){
byte [] raw = File.ReadAllBytes(filePath);
WWWForm form = new WWWForm();
form.AddBinaryData("fileUpload", raw, "", "text/xml");
WWW www = new WWW(host + auth + "/behaviors", form);
StartCoroutine(myCoroutine(www));
}
IEnumerator myCoroutine(WWW www){
yield return www;
if (www.error == null)
{
Debug.Log("Text: " + www.text);
proceedToNextRequest = true;
} else {
Debug.Log("Error: "+ www.error);
Application.Quit();
}
}
The answer from the server is, though, "Unsupported Media Type", and I've no idea what's wrong. I generally use POSTMAN on Google Chrome to send these requests, and it works fine. Any tips?
I have found a solution for this: instead of using the WWW class(which, anyway, according to the documentation I'm pretty sure it can be used for this pupose), I'm using WebRequest. How this can be achieved is very well explained in the previous link and in this question: HTTP post XML data in C#

Categories

Resources