I am using UnityWebRequest to update (PUT) Raw JSON on the server. Unfortunately I get the error HTTP/1.1 405 Method Not Allowed. I am assuming that I am not Encoding it correctly. What could be the issue here?
This is a follow up question asked by my colleague: HTTP Method Not Allowed in REST API Post
We have tried to encode it in different ways as given below in the script. Unfortunately it does not work.
We have this JSON online and to enter data (PUT), it is a must to have the name and address fields as non-empty.
IEnumerator Post()
{
byte[] myData = System.Text.Encoding.UTF8.GetBytes("{'name': 'User01', 'address':{'raw':'MountFiji'}}");
UnityWebRequest www = UnityWebRequest.Put("website_of_the_user", myData);
www.SetRequestHeader("Content-Type", "application/json");
yield return www.SendWebRequest();
if(www.isNetworkError || www.isHttpError) {
Debug.Log(www.error);
}
else {
Debug.Log("Upload complete!");
}
}
{
"name": "",
"address": {
"raw": ""
}
}
The webpage where we have our API has following properties:
HTTP 200 OK
Allow: GET, HEAD, PUT, OPTIONS, DELETE
Content-Type: application/json
I got it working. If anyone in future faces this problem, then the solution is simpler than you think. The problem was the JSON format code, it is important to give \ since the data is a string. Here is the complete code:
UnityWebRequest www = UnityWebRequest.Put(URL_01, "{\"name\":\"user_01\",\"address\":{\"raw\":\"MountFiji\"}}");
www.SetRequestHeader ("Content-Type", "application/json");
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
}
else
{
Debug.Log("Form upload complete!");
}
Related
So I have to make a method in asp.net for an API that accepts 2 files via PUT (1 json and 1 xml for processing data, not saving- because I have to, OK? :) ), sending the request via fiddler..
Right now I'm sending the request like this on fiddler (PUT METHOD):
Content-Type: multipart/form-data
Authorization: XXXXX
Host: XXXX
Request body:
<#INCLUDE *C:\Users\ZZZZ.json*#>
<#INCLUDE *C:\Users\XXXX.xml*#>
Here's what I've tried inside the controller so far:
[HttpPut, Route("api/Student/{studentId}/Classes/{classId}")]
public async Task<string> Put(int studentId, int classId)
{
var file = HttpContext.Current.Request.Files.Count > 0 ?
HttpContext.Current.Request.Files[0] : null;
Stream fileContent = await this.Request.Content.ReadAsStreamAsync();
MediaTypeHeaderValue contentTypeHeader = this.Request.Content.Headers.ContentType;
if (fileContent != null)
return "ok";
return "not ok";
}
So far the file is not being uploaded nor appears within the request (everything's null). I've also tried the "Request" variable and HttpContext.
Tried the exact same thing but with a POST Method (including the boundaries) and the same happens.
What would you do in order to make this work? I really have to send a json object and another in xml, I really can't change languages or send everything in json ('cause that I could make it work)...
PS: The files don't have a defined structure, it has to be dynamic
PS2 : How would you then attempt to read those files without actually saving them?
You don't have to use a stream to read the file content. You can just try using the HttpPostedFile.
[HttpPut, Route("api/student/{studentId}/classes/{classId}")]
public async Task<string> Put(int studentId, int classId)
{
if (HttpContext.Current.Request.Files.Count == 0)
throw new HttpResponseException(new HttpResponseMessage()
{
ReasonPhrase = "Files are required",
StatusCode = HttpStatusCode.BadRequest
});
foreach (string file in HttpContext.Current.Request.Files)
{
var postedFile = HttpContext.Current.Request.Files[file];
if (!(postedFile.ContentType == "application/json" || postedFile.ContentType == "application/xml"))
{
throw new System.Web.Http.HttpResponseException(new HttpResponseMessage()
{
ReasonPhrase = "Wrong content type",
StatusCode = HttpStatusCode.BadRequest
});
}
}
return "OK";
}
POSTMAN
My POSTMAN:
enter image description here
Fiddler
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)
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.
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.
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#