Unity Facebook : 400 Bad Request - facebook

I using following code to get user data from facebook
IEnumerator UserFBDataGet(string accessTkn)
{
var downloader3 = new WWW ( "https://graph.facebook.com/me?fields=id,name,email&access_token="+accessTkn );
//Application.OpenURL ( "https://graph.facebook.com/me?fields=id,name,email&access_token="+accessTkn );
yield return downloader3;
print(" downloader3.text ="+downloader3.text );
if(downloader3.error == null)
{
print(" downloader3.text ="+downloader3.text );
}
else
{
print(" downloader3.error ="+downloader3.error );
}
}
It showing Error
You are trying to load data from a www stream which had the following error when downloading.
400 Bad Request
UnityEngine.WWW:get_text()
c__Iterator1:MoveNext() (at Assets/FBDesktopManager.cs:126)
Even i use WWWForm same error is showing
IEnumerator UserFBDataGet(string accessTkn)
{
userDataGetUrl = "https://graph.facebook.com/me?";
WWWForm wf = new WWWForm();
wf.AddField ("fields","id,name,email") ;
wf.AddField ("access_token",accessTkn) ;
WWW downloader3 = new WWW(userDataGetUrl,wf) ;
yield return downloader3;
print(" downloader3.text ="+downloader3.text );
if(downloader3.error == null)
{
print(" downloader3.text ="+downloader3.text );
}
else
{
print(" downloader3.error ="+downloader3.error );
}
}
But when I call
Application.OpenURL ( "https://graph.facebook.com/me?fields=id,name,email&access_token="+accessTkn );
in that page i get all data properly.

Your url needs to be '%' escaped. Besides unity suggests using WWWForm to pass POST parameters properly.

Related

UnityWebRequest with cookie authentication

So i was trying to get a data with an user profile API where you need cookies authorization to make it work, and i can't really get and/or set the cookies for the target website.
here's the code that i'm currently using(to get the data from target url), the cookie that act as authorization was called .AspNet.ApplicationCookie
IEnumerator GetData_Coroutine()
{
using (UnityWebRequest request = UnityWebRequest.Get("Target URL"))
{
if (cookie != "")
{
request.SetRequestHeader(".AspNet.ApplicationCookie", "Content in it");
}
yield return request.SendWebRequest();
if (request.result== UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
{
outputArea.text = request.error;
}
else
{
if (outputArea != null)
{
outputArea.text = request.downloadHandler.text;
}
}
}
}
and here's the outcome i've got
p/s: i'm quite new to networking. So feel free to point out if there's any mistakes that i'm not aware of
After several trial and error, turns out that my mistake comes from the header name from SetRequestHeader
it's name should be the header, while the content should be the whole thing it has
you should be able to see it from web debugger, while the text shown is their name you should put first, their content will be the second one
so the code should be like this:
public string cookieContent
IEnumerator GetData_Coroutine()
{
using (UnityWebRequest request = UnityWebRequest.Get("Target URL"))
{
if (cookie != "")
{
request.SetRequestHeader("cookie", cookieContent);
}
yield return request.SendWebRequest();
if (request.result== UnityWebRequest.Result.ConnectionError || request.result == UnityWebRequest.Result.ProtocolError)
{
outputArea.text = request.error;
}
else
{
if (outputArea != null)
{
outputArea.text = request.downloadHandler.text;
}
}
}
}

After updating to unity 2021.1.13.f1 isNetworkError and isHttpError is already obselete

if (www.isNetworkError || www.isHttpError)
{
Debug.Log(www.error);
}
Does anyone know how to replace this code properly to the updated one
Starting from Unity 2020.2 you now use UnityWebRequest.result
Example from UnityWebRequest.Get
using (UnityWebRequest webRequest = UnityWebRequest.Get(uri))
{
// Request and wait for the desired page.
yield return webRequest.SendWebRequest();
string[] pages = uri.Split('/');
int page = pages.Length - 1;
switch (webRequest.result)
{
case UnityWebRequest.Result.ConnectionError:
case UnityWebRequest.Result.DataProcessingError:
Debug.LogError(pages[page] + ": Error: " + webRequest.error);
break;
case UnityWebRequest.Result.ProtocolError:
Debug.LogError(pages[page] + ": HTTP Error: " + webRequest.error);
break;
case UnityWebRequest.Result.Success:
Debug.Log(pages[page] + ":\nReceived: " + webRequest.downloadHandler.text);
break;
}
}
Or the simplier example from UnityWebRequest.Post
WWWForm form = new WWWForm();
form.AddField("myField", "myData");
using (UnityWebRequest www = UnityWebRequest.Post("https://www.my-server.com/myform", form))
{
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.Log(www.error);
}
else
{
Debug.Log("Form upload complete!");
}
}
I solve mine like that!
instead using: if(www.isNetworkError)
I wrote: if(www.result == UnityWebRequest.Result.ConnectionError)
Full example is below:
IEnumerator Get(string url)
{
using (UnityWebRequest www = UnityWebRequest.Get(url))
{
yield return www.SendWebRequest();
if (www.result == UnityWebRequest.Result.ConnectionError)
{
Debug.LogError(www.error);
}
}
}
Replace "www.isHttpError" with "(www.result== UnityWebRequest.Result.ProtocolError)" and "www.isNetworkError" with "(www.result == UnityWebRequest.Result.ConnectionError)".
Assuming www means the request object.

Using Post Request return a multiple values in Unity

I am new to Unity i have created a Post Request from that i want to return the Authentication-Token Header and authorization header and some required json data here is my code
private IEnumerator BasketId()
{
string url = "http://hololens5.northeurope.cloudapp.azure.com/INTERSHOP/rest/WFS/inSPIRED-inTRONICS-Site/-/baskets/";
using (UnityWebRequest request = UnityWebRequest.Post(url, "Hello"))
{
yield return request.SendWebRequest();
string token = request.GetResponseHeader("Authentication-token");
if (request.isNetworkError || request.isHttpError)
{
Debug.Log(request.error);
}
else
{
string jsonResut = System.Text.Encoding.UTF8.GetString(request.downloadHandler.data);
obj = JsonConvert.DeserializeObject<BasketId>(jsonResut);
Debug.Log(obj.Uri);
Debug.Log("Authentication-Token: " + token);
yield return obj.Title;
yield return token;
}
}
}
so i could i return the values. Please help me.
Because Coroutine is not immediate (blocking) so you won't be able to return the response directly. What you need to do is to have an event or callback that will be called when your request completed.
Here is how you can achieve it by passing the callback as argument:
private IEnumerator GetBasketId(System.Action<string, BasketId> callback)
{
string url = "http://hololens5.northeurope.cloudapp.azure.com/INTERSHOP/rest/WFS/inSPIRED-inTRONICS-Site/-/baskets/";
using (UnityWebRequest request = UnityWebRequest.Post(url, "Hello"))
{
yield return request.SendWebRequest();
if (request.isNetworkError || request.isHttpError)
{
Debug.Log(request.error);
if (callback != null)
{
callback(null, null);
}
// callback?.Invoke(null, null); // for short
}
else
{
if (callback != null)
{
string token = request.GetResponseHeader("Authentication-token");
string jsonResut = System.Text.Encoding.UTF8.GetString(request.downloadHandler.data);
obj = JsonConvert.DeserializeObject<BasketId>(jsonResut);
if (callback != null)
{
callback(token, obj);
}
// callback?.Invoke(token, obj); // for short
}
}
}
}
so when you want to start the request simply call something like:
StartCoroutine(GetBasketId((token, basketId) =>
{
if (string.IsNullOrEmpty(token))
{
// Handle error
}
else
{
// Handle success
Debug.Log("Token: " + token);
Debug.Log(basketId.Title);
}
});

How can I get all post ids for a Facebook page?

I am using https://graph.facebook.com/v2.4/page_id/posts?fields=id to get all post ids from a Facebook page, but I am running into an infinite loop issue with pagination due to paging.next property always returning a url. It looks like the last page points to the first page. How would I know I have reached the end of results.
Here is a code example:
public static Dictionary<string,string> GetPagePostIds(string accessToken, string pageId)
{
Dictionary<string, string> postIds = new Dictionary<string, string>();
StringBuilder sb = new StringBuilder(graphAPIURL);
sb.Append("/").Append(pageId).Append("/posts/?access_token=").Append(accessToken);
sb.Append("&fields=id");
string url = sb.ToString();
int pages = 0;
int rows = 0;
while (url != null)
{
System.Net.WebRequest req = System.Net.WebRequest.Create(url);
System.Net.WebResponse response = req.GetResponse();
string json = null;
using (System.IO.StreamReader sr = new System.IO.StreamReader(response.GetResponseStream()))
{
json = sr.ReadToEnd();
Console.WriteLine(json);
}
if (json != null)
{
pages++;
Dictionary<string, dynamic> data = (Dictionary<string, dynamic>)Newtonsoft.Json.JsonConvert.DeserializeObject(json, typeof(Dictionary<string, dynamic>));
if (data.ContainsKey("data"))
{
Newtonsoft.Json.Linq.JArray a = (Newtonsoft.Json.Linq.JArray)data["data"];
foreach (Newtonsoft.Json.Linq.JObject o in a)
{
rows++;
postIds.Add(o["id"].ToString(), o["id"].ToString());
}
}
if (data.ContainsKey("paging"))
{
try
{
if (data["paging"]["next"] == url)
{
//otherwise we will be stuck in the infinite loop, as next url of the last page is not null
break;
}
//if next link is present, there are more pages available
url = null;
url = data["paging"]["next"];
}
catch (Exception)
{
}
}
}
}
return postIds;
}
You can break the loop, if you reach to the point, where you only receive empty results.
So you just simply extend your while loop with a second condition. Here is some simple pseudocode:
while (url != null && resultsOnPage) {
[...]
if (data.ContainsKey("data") && data['data'].Count > 0 ) {
[...]
} else {
resultsOnPage = false;
}
[...]
}
Just leave the rest as it is.

as3-fb-api: how is it possible to have an accesstoken BEFORE Facebook.init()

the Facebook.init method of the as3-facebook-api (for flash) allows for an optional accesstoken parameter.
But the whole point of the .init(...) method is to, well, init everything ... accesstokens are a byproduct of the init phase.
So how is it possible to even have an accesstoken in the first place.
(Please do not respond with a rhetorical answer ... I am looking for a app-practical answer ... thanks).
The access token is valid for a specific amount of time, so technically you could reuse it. That, or you could have connected to Facebook using another language and have a token from that (more common than you'd think)
Edit 24/05/2012
Ok, After running some tests, and looking at the code in the Facebook AS3, this is what I have:
You're right in that you have to call Facebook.init() first, before you do anything. Otherwise, you just get errors everywhere
Passing an accessToken won't do anything unless you also pass and options Object with status = false (so your init() call becomes Facebook.init( APP_ID, this._onInit, {status:false}, myAccessToken);)
Basically what it does is inits the lib, but doesn't call the getLoginStatus() external event, so you're saving a few calls and your program starts quicker - that's about it as far as I could tell.
If you don't care about the lib, and you have an access token, technically you could bypass init() altogether, and just append ?access_token=[myToken] to the end of your urls when you call api() (e.g. Facebook.api( "/me?access_token=" + myAccessToken, this._onInfo );) - or skip the lib entirely, and just make a URLLoader request to the url
A simple example showing all of this. Create your app as normal, substitute your app id, and connect normally. It'll trace out your uid and access token. Copy the token, launch the app again, and paste the token into the input area. It'll now use this when you init() again.
package
{
import com.facebook.graph.data.FacebookAuthResponse;
import com.facebook.graph.Facebook;
import flash.display.Sprite;
import flash.events.KeyboardEvent;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFormat;
import flash.ui.Keyboard;
import flash.utils.getQualifiedClassName;
/**
* Test facebook connect, showing the init() call with and without an access token. Make a normal
* connection, then copy the access token, and reload. paste your token into the input area to use
* it for the init() call
* #author Damian Connolly
*/
public class Main extends Sprite
{
private static const APP_ID:String = "[SET_YOUR_APP_ID]";
private var m_tf:TextFormat = new TextFormat( "Trebuchet Ms", 9 );
private var m_input:TextField = null; // for adding the token
private var m_log:TextField = null; // for logging our messages
public function Main():void
{
// create our input
this.m_input = new TextField;
this.m_input.defaultTextFormat = this.m_tf;
this.m_input.border = true;
this.m_input.background = true;
this.m_input.type = TextFieldType.INPUT;
this.m_input.text = " ";
this.m_input.width = 700.0;
this.m_input.height = this.m_input.textHeight + 4.0;
this.m_input.text = "";
this.m_input.x = this.m_input.y = 10.0;
this.addChild( this.m_input );
// log and add our mouse listeners
this._log( "Press [SPACE] to init facebook connection, [CTRL] to login, [SHIFT] to get data" );
this._log( "Copy a pre-existing token into the textfield above to use it in the init() call" );
this.stage.addEventListener( KeyboardEvent.KEY_DOWN, this._onKeyDown );
}
// keyboard listener
private function _onKeyDown( e:KeyboardEvent ):void
{
if ( e.keyCode == Keyboard.SPACE )
this._init();
else if ( e.keyCode == Keyboard.CONTROL )
this._login();
else if ( e.keyCode == Keyboard.SHIFT )
this._getData();
}
// init our facebook api
private function _init():void
{
// use our token if we have one
var token:String = ( this.m_input.text != "" ) ? this.m_input.text : null;
this._log( "---------- Initing facebook with token '" + token + "'" );
if ( token == null )
Facebook.init( Main.APP_ID, this._onInit );
else
{
var options:* = { status:false };
Facebook.init( Main.APP_ID, this._onInit, options, token );
}
}
// callback for init
private function _onInit( success:*, fail:* ):void
{
this._log( "Callback for init 2! success: " + success + ", fail: " + fail );
this._log( "Success: " + getQualifiedClassName( success ) );
this._log( "Fail: " + getQualifiedClassName( fail ) );
var response:FacebookAuthResponse = success as FacebookAuthResponse;
if ( response != null )
this._log( "UID: " + response.uid + ", access token: " + response.accessToken );
this._log( ( success != null ) ? "Logged in" : "Not logged in" );
}
// logs into the app if we need to
private function _login():void
{
this._log( "---------- Logging in" );
Facebook.login( this._onLogin );
}
// callback for the login
private function _onLogin( success:*, fail:* ):void
{
this._log( "Callback for _onLogin! success: " + success + ", fail: " + fail );
this._log( "Success: " + getQualifiedClassName( success ) );
this._log( "Fail: " + getQualifiedClassName( fail ) );
var response:FacebookAuthResponse = success as FacebookAuthResponse;
if ( response != null )
this._log( "UID: " + response.uid + ", access token: " + response.accessToken );
}
// gets our data
private function _getData():void
{
this._log( "---------- getting data with url '/me'" );
Facebook.api( "/me", this._onGetData );
}
// callback for our data
private function _onGetData( success:*, fail:* ):void
{
this._log( "Callback for _onLogin! success: " + success + ", fail: " + fail );
this._log( "Success: " + getQualifiedClassName( success ) );
for ( var key:* in success )
this._log( " key '" + key + "' = " + success[key] );
this._log( "Fail: " + getQualifiedClassName( fail ) );
}
// logs a message to the console and our textfield
private function _log( msg:String ):void
{
// create our log if needed
if ( this.m_log == null )
{
this.m_log = new TextField;
this.m_log.defaultTextFormat = this.m_tf;
this.m_log.border = true;
this.m_log.background = true;
this.m_log.width = 700.0;
this.m_log.height = 200.0;
this.m_log.x = this.m_input.x;
this.m_log.y = this.m_input.y + this.m_input.height + 5.0;
this.m_log.wordWrap = true;
this.addChild( this.m_log );
}
trace( msg );
this.m_log.appendText( msg + "\n" );
}
}
}