Unity post to api empty data - unity3d

Strange problem.
As of what I read on the internet and
find in the unity documentation;
This should be the correct way to post from unity to an API server.
// create new form
formData = new List<IMultipartFormSection>();
// create param
formData.Add(new MultipartFormDataSection("m_board_id=" + boardId));
//1. Generate UnityWebRequest (UnityWebRequestを生成)
UnityWebRequest request = UnityWebRequest.Post("[my website link]", formData);
using (request)
{
yield return request.SendWebRequest();
if (request.isHttpError || request.isNetworkError)
{
Debug.Log(request.error);
}
else
{
Debug.Log("succes");
}
}
When I do this; the link is executed, but the formData isn't sent with it.
The data is empty!
When I do a request like this;
UnityWebRequest request = UnityWebRequest.Post("[my website api link]?m_board_id=" + boardId, formData);
It works and the database is updated.
The formData is still empty!
I guess this wouldn't be the right way to execute a post request from unity, right?
What am I doing wrong here with the formData.Add function?
Anybody that can send me in the right direction?
I would love to learn more about unity.
Thank you in advance.
Wesley

Related

I POST my image by python through WP REST API, but the response is just the array of items in media library

First of all, I have found out what's wrong with my python code, but I really want some one to tell me how it popped out because I'm just a noob amateur.
I tried to post my album collected on my wordpress by using my python script as usual, but I got an unexpected throw-out when it start to image upload. My img upload function just like this:
def restImgUL(imgPath,imgName,token):
url='http://www.rainloongmusic.com/wp-json/wp/v2/media/'
file_extension = os.path.splitext(imgPath)[-1]
img = open(imgPath,'rb')
imgName = imgName.replace(";","")
_json = {
"title":imgName,
'caption': imgName,
"alt_text":imgName,
"description":imgName,
"status":"publish"
}
image_name = f"{imgName}{file_extension}"
headers = { 'Content-Type': '','Content-Disposition' : 'attachment; filename=%s'%image_name.encode("utf-8").decode("latin1"),"Authorization":"Bearer %s"%token}
res = requests.post(url=url,data=img,headers=headers,json=_json)
rrr = res.json()
if "id" in rrr:
return rrr["id"]
else:
print(rrr)
sys.exit()
The wrong response is an array include items in my first page of media library. I found some clues in rest api handbooks. If I attempt to GET /wp/v2/media, response will be like what I've recieved. But I use POST type request in my python code, I don't really understand what happened there. I have no choice but to try some other methods to bypass this problem. I tried to make a new endpoint and write something like this:
add_action( 'rest_api_init', function () {
register_rest_route( 'rlra/v1', '/media', array(
'methods' => 'POST',
'callback' => 'cmupload',
) );
} );
function cmupload(){
return "This is a test!!!"
}
However, I got rest_no_route when I POST to it. I changed the methods to GET eventually, and got the right text from my server. I think maybe something changed my POST request into a GET one? I tried to figure out with Charles, and found my connection with 302 permanent redirect. So I check my request link and change http into https, everything works.
So, could anyone tell me why a 302 redirect will change my POST request into GET, I've been worn-out due to the lost letter "s" in these days.

UnityWebRequest data is blank

I am using a flask server and having Unity access it. Testing it in Postman (with platform:test) gives me ImmutableMultiDict([('platform', 'test')]) (result of request.form in Flask) which works. But when unity makes a post request (code provided), it gives me ImmutableMultiDict([]). I'm not completely sure if this is a Unity or a Flask problem. Help is much appreciated.
IEnumerator PostRequest(string url)
{
WWWForm form = new WWWForm();
form.AddField("platform", "test");
UnityWebRequest uwr = UnityWebRequest.Post(url, form);
uwr.uploadHandler.contentType = "multipart/form-data";
yield return uwr.SendWebRequest();
if (uwr.isNetworkError)
{
Debug.Log("Error While Sending: " + uwr.error);
}
else
{
Debug.Log("Received: " + uwr.downloadHandler.text);
}
}
I have fixed the issue.
Unity formats its data wildly different from PostMan, and my Flask server couldn't read it. Instead of using request.form[key] or request.data[key] in Flask, I found request.form.getlist(key) worked perfectly with both Postman's requests and Unity's.

create token in unity to send post request to laravel controller

I wanna send a post request from a unity game to a laravel 5.4 controller.. in html form, we use {{csrf_field}} and it handles creating token. but how can I do it in unity?
I came across this thread whilst trying to acheive what it set out to do - and I got it working so I am sharing this:
It is a combination of this tutorial on YouTube: How to Use UnityWebRequest - Replacement for WWW Class - Unity Tutorial and this answer on a similar question: UnityWebRequest POST to PHP not work
The technology I am using:
Laravel Framework 7.15.0 (PHP)
Unity: 2019.3.11f1 (script is C#)
Now I am just sending basic forms not images etc - so I haven't tried anything complex but this sends a get to one URL on Laravel which returns the CSRF token.
This is then added as an additional field to the post request.
I am clicking the 2 buttons pretty quickly - I would suggest (and will implement this myself later) that you don't ask for the token until your ready to submit the form - to avoid it expiring if your form is quite long etc.
The C# Script (Unity)
Both the functions are set as ON Click() on the buttons in a simple UI Canvas in Unity.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
public class BasicWebCall : MonoBehaviour
{
public Text messageText;
public InputField scoreToSend;
private string csrf_token;
readonly string getURL = "http://mazegames.test/leaderboard/1";
readonly string postURL = "http://mazegames.test/register/1";
private void Start()
{
messageText.text = "Press buttons to interact with web server";
}
public void OnButtonGetScore()
{
messageText.text = "Getting Token";
StartCoroutine(SimpleGetRequest());
}
IEnumerator SimpleGetRequest()
{
UnityWebRequest www = UnityWebRequest.Get(getURL);
yield return www.SendWebRequest();
if(www.isNetworkError || www.isHttpError)
{
Debug.LogError(www.error);
}
else
{
messageText.text = "Token Received: " + www.downloadHandler.text;
csrf_token = www.downloadHandler.text;
}
}
public void OnButtonSendScore()
{
if (scoreToSend.text == string.Empty)
{
messageText.text = "Error: No high score to send.\nEnter a value in the input field.";
}
else
{
messageText.text = "Sending Post Request";
StartCoroutine(SimplePostRequest(scoreToSend.text));
}
}
IEnumerator SimplePostRequest(string curScore)
{
Dictionary<string, string> wwwForm = new Dictionary<string, string>();
wwwForm.Add("_token", csrf_token);
UnityWebRequest www = UnityWebRequest.Post(postURL, wwwForm);
yield return www.SendWebRequest();
if (www.isNetworkError || www.isHttpError)
{
Debug.LogError(www.error);
}
else
{
messageText.text = www.downloadHandler.text;
}
}
}
Laravel routes/web.php
Obviously you need to configure your end points to receive your data, validate and store it if necessary. In this example its just validating the token as part of the post request.
Route::post('register/{game_id}', function($game_id) {
return "Game On!";
});
Route::get('leaderboard/{game_id}', function($game_id) {
return csrf_token();
});
And that is pretty much it - hope this helps someone else.
#EDIT# - Request Token on Submission
To only get the token when your submitting the form, literally all you have to do is put this line:
StartCoroutine(SimpleGetRequest());
above the line:
StartCoroutine(SimplePostRequest(scoreToSend.text));
so that is looks like this:
StartCoroutine(SimpleGetRequest());
StartCoroutine(SimplePostRequest(scoreToSend.text));
Obviously you could then remove the function SimpleGetRequest altogether.
Laravel will generate a token each time a page is generated. The token has a lifetime and after that lifetime it cannot be used anymore (that's the whole point).
You need to get a valid token from Laravel pass it to Unity3D and then when from Unity create a WWWForm and pass it back.
How to do this it depends on the platform that Unity3D is deployed to.
If you are using WebPlayer or WebGL then you can get your hand on the Unity3D objected embedded in the browser and use SendMessage. WebGL link here.
If the game is deployed to another platform it probably makes sense to expose and API on the Laravel side and use that endpoint instead of doing a POST request.
You can use WWWForm to send in POST and call it from a coroutine:
// this will send it at start
// but you can just call SendToController in another function
string laravel_url = "http://somedomain.com/whatever";
IEnumerator Start () {
yield return StartCoroutine(SendToController());
}
IEnumerator SendToController()
{
WWWForm form = new WWWForm();
form.AddField( "csrf_field", "replace this with what you want!!!!" );
WWW download = new WWW( laravel_url, form );
yield return download;
if(!string.IsNullOrEmpty(download.error)) {
print( "Error downloading: " + download.error );
} else {
// if succesful, do what you want
Debug.Log(download.text);
}
}
"Coroutine" is your friend. It will make sending forms a lot easier. You might want to read about it in here:
https://docs.unity3d.com/ScriptReference/MonoBehaviour.StartCoroutine.html

How do I get the redirect url?

I want to get a redirect url from a url.
Url:
https://api.soundcloud.com/tracks/151935719/stream?client_id=
redirect url looks something like this:
https://ec-media.soundcloud.com/0fdDn45vb5t4.128.mp3?f10880d39085a94a0418a7ef69b03d522cd6dfee9399eeb9a522019d6afabf3e3c10bce51c30cbe03f40dfc788e191ee959a960c826c0a5de46a851702613b05f3906a2971&AWSAccessKeyId=AKIAJNIGGLK7XA7YZSNQ&Expires=1401521245&Signature=B3P8qLw1t%2BQ2oYQUEfpep9%2FULXg%3D
How do I get the redirect url so I can stream from this link?
I am using C# WPF and I am a newbie.
Thanks!!
It should be automatic with HttpWebRequest.AllowAutoRedirect:
HttpWebRequest request = HttpWebRequest.CreateHttp(yourURI);
request.AllowAutoRedirect = true;
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
// Your code
}
However, the default value for AllowAutoRedirect is true, so, in general, you shouldn't even need to set it. Redirection is automatically handled:
HttpWebRequest request = HttpWebRequest.CreateHttp(yourURI);
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
// Your code
}

Get track.stream_url returning garbage

I am trying to stream SoundCloud songs using JPlayer in a Ruby on Rails application. I try to get the stream url server-side using this:
#stream_url = client.get(#track.stream_url, :allow_redirects => true)
I then try to load this URL using JPlayer like so:
<script type="text/javascript">
$("#jquery_jplayer_1").jPlayer({
ready: function() {
$(this).jPlayer("setMedia", {
mp3: "<%= #stream_url %>"
});
},
swfPath: "/js",
supplied: "mp3"
});
</script>
But when I load the page, the browser chokes on the URL string. The returned markup and script looks like this:
$(this).jPlayer("setMedia", {
mp3: "���DInfo+4F��!$&)+.0368;=#..."
That string goes on for much longer than I'll post here.
My best guess is that this is an encoding issue, but I can't figure it out. I've tried in the rails console to debug, but that got me nowhere.
Any ideas would be appreciated. Thanks!
It seems like there are some encoding issues you are facing with.
When I send the HTTP request manually and get the endpoint URL in C#, I don't face the same problem and the end the endpoint URL of the audio is perfectly fine.
public void Run()
{
if (!string.IsNullOrEmpty(TrackUrl))
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(TrackUrl + ".json?client_id=YOUR_CLIENT_ID");
request.Method = "HEAD";
request.AllowReadStreamBuffering = true;
request.AllowAutoRedirect = true;
request.BeginGetResponse(new AsyncCallback(ReadWebRequestCallback), request);
}
}
private void ReadWebRequestCallback(IAsyncResult callbackResult)
{
HttpWebRequest myRequest = (HttpWebRequest)callbackResult.AsyncState;
HttpWebResponse myResponse = (HttpWebResponse)myRequest.EndGetResponse(callbackResult);
using (StreamReader httpwebStreamReader = new StreamReader(myResponse.GetResponseStream()))
{
this.AudioStreamEndPointUrl = myResponse.ResponseUri.AbsoluteUri;
this.SearchCompleted(this);
}
myResponse.Close();
}
Don't know how that is it applies to Ruby on Rails but you get the idea.
You can try a similar trick to this one instead of using the client.get method.