i am having a strange problem.
I use OAuth2 and gapi.auth.authorize({client_id:'...',scope:'../youtube',immediate:false}) to log a user into my app. This method lets the user choose which of his connected accounts(identities) to use.
I retrieve user's video using gapi.client.youtube.channels.list and gapi.client.youtube.playlistItems.list.
later in the same app the user can click a button to choose another of his connected accounts(identities). i use again gapi.auth.authorize({client_id:'...',scope:'../youtube',immediate:false}) method.
the problem is that after successfull change of the account the gapi.client.youtube.channels.list method returns the cached result from the first call.
some remarks:
-in ie 11 it works fine
- in google chrome, if i disable the cache from developers tools it also works fine
- before the call to channels.list i call /oauth2/v2/tokeninfo and /plus/v1/people/me and they both return correct results, that is the second account's data
is there any way to correct this?
thank you.
Someone can overcome this by using XMLHttpRequest( see https://developers.google.com/api-client-library/javascript/features/cors) . It's probably a bug of javascript YouTube api.
What worked for me is to introduce a silly extra parameter on the request to cheat Google's system... Or at least that's my impression, because it seems to work consistently:
I just add it to the URL:
"https://www.googleapis.com/youtube/v3/channels?mine=true" +
"&part=" + encodeURIComponent("id,snippet") +
"&key=" + encodeURIComponent(API_KEY) +
"&random=" + encodeURIComponent(Math.random().toString())
Here's the full example:
refreshChannels(): Promise<YoutubeChannel[]> {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
this.channels = JSON.parse(xhr.response).items.map(ch => new YoutubeChannel().deserialize(ch));
console.log("[Youtube][loadChannels] Got some channels:");
console.log(this.channels);
this.onReceivedYoutubeChannels.next(this.channels);
resolve(this.channels);
} else {
reject(JSON.parse(xhr.response));
}
}
};
xhr.onerror = () => reject();
const user = gapi.auth2.getAuthInstance().currentUser.get();
const oAuthToken = user.getAuthResponse().access_token;
xhr.open(
"GET",
"https://www.googleapis.com/youtube/v3/channels?mine=true&part=" +
encodeURIComponent("id,snippet") +
"&key=" +
encodeURIComponent(API_KEY) +
"&random=" + encodeURIComponent(Math.random().toString())
);
xhr.setRequestHeader("Authorization", "Bearer " + oAuthToken);
xhr.send();
});
}
I get different ETags. I saw as well a Cache-Control response header that might be caching too?
cache-control: private, max-age=300, must-revalidate, no-transform
With my solution I can overcome it. If someone understands why it would be great if could elaborate more on this solution.
Related
I have IOS app based on phonegap, I want to redirect it to responsive website and set cookies to still logged in with his credentials.
windows.location is not work
Thanks
use "window.location.href"
window.location.href = "your website url here"
it will solve the problem on iOS
I found the solution
function scripting() {
ref.executeScript({
code: 'document.cookie = "token=' + res.data.token + '"; window.location= "' + res.redirectUrl + '"; '
}, function () {
ref.removeEventListener('loadstart', scripting);
});
}
var ref = cordova.InAppBrowser.open(res.redirectUrl, '_blank', 'location=no,toolbar=no');
ref.addEventListener('loadstart', scripting);
I hope it helps who had the same problem
ok after two days of tryouts i still cant my titanium application to play well with twitter request_token api 1.1, i am always getting 401 unauthorized error .below is my code. i am blocked so any help is appreciated.
var httpClient = Ti.Network.createHTTPClient({
onerror : function(e) {
alert(this.status + ":" + e.error);
},
onload : function(e) {
alert(this.responseText);
if (this.readyState == 4) {
var resposeText = this.responseText;
}
}
});
httpClient.open('POST', "https://api.twitter.com/oauth/request_token");
httpClient.setRequestHeader("content-type", "application/x-www-form-urlencoded; charset=UTF-8");
var now = new Date().getTime();
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
var nonce = "";
for (var i = 0; i < 10; ++i) {
var rnum = Math.floor(Math.random() * chars.length);
nonce += chars.substring(rnum, rnum + 1);
}
var parameters = "oauth_callback=" + Ti.Network.encodeURIComponent("http://apicallback.stc.com.sa");
var signature = "POST&" + Ti.Network.encodeURIComponent("https://api.twitter.com/oauth/request_token") + "&" + Ti.Network.encodeURIComponent(parameters);
var header = "OAuth oauth_callback=\"" + Ti.Network.encodeURIComponent("http://apicallback.stc.com.sa") + "\",oauth_consumer_key=\"wPdlchopdYaqHhab8H8jMA\",oauth_nonce=\"" + nonce + "\",oauth_signature=\"" + signature + "\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"" + now + "\",oauth_version=\"1.0\"";
httpClient.setRequestHeader("Authorization", header);
httpClient.send(parameters);
There were several errors :
Your nonce seems to be built incorrectly. Generate a string with 32 letters and encode it with Base 64.
Your signature is not built correctly too. Refer to the Twitter Developers documentation about making signatures. Here are your errors :
All the OAuth arguments are missing but oauth_callback. The OAuth arguments which are used in the Authorize header have to be included in the parameters for the signature
You do not build the key to sign datas.
You do not use the signature method (oauth_signature_method which is set to "HMAC-SHA1") to sign your datas.
Your timestamp is too big. It is the number of seconds since the Unix Epoch time, not the milliseconds. Add a "/1000" :
var now = new Date().getTime() / 1000
More generally have a look at Twitter Developers documentation about authorizing requests : https://dev.twitter.com/docs/auth/authorizing-request
by chance i found javascript library posted in twitter list of libraries. check it out jsOAuth. there is also API doc for the library :). now i am able to get the authorization token but when i perform search by posting to https://api.twitter.com/1.1/search/tweets.json i get 401 (unauthorized) error. now i am stuck again. any idea what might be the problem...
There are multiple twitter libraries out there for appcelerator that already work, I would suggest starting with one of them.
http://www.clearlyinnovative.com/blog/post/33810421717/titanium-appcelerator-quickie-posting-images-to-twitter-with-social_plus-js
see link to github repo at bottom of posting
I'm trying to use CORS against the Youtube API from a single page app. The point is to avoid a full page reload (like http://gdata-samples.googlecode.com/svn/trunk/gdata/youtube_upload_cors.html is doing). There are generally two ways this can be done:
Using a hidden iframe
or
using XMLHttpRequest with FormData
The latter is most elegant, but not supported in some inferior browsers. I'm in the lucky position that I may ignore those browsers.
Now I wrote the following code:
var fd = new FormData();
fd.append('token', token);
fd.append('file', element.files[0]);
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", uploadProgress, false);
xhr.addEventListener("load", uploadComplete, false);
xhr.addEventListener("error", uploadError, false);
xhr.addEventListener("abort", uploadAbort, false);
xhr.open("POST", $scope.uploadData.uploadUrl + '?nexturl=' + $location.absUrl());
xhr.send(fd);
This works (as in, it uploads the whole file, whilst emitting progress events happily), but at the end it errors out. I'm not sure what I'm doing wrong, but I'd really love to see a sample using this strategy instead of the full page refresh. Especially dealing with the response and the id in there I am very curious about.
Have you got something like this working?
It's possible by using Direct Uploading API v2 and FormData + XHR2. Something like:
var DEV_KEY = '<here application key: you can find at https://code.google.com/apis/youtube/dashboard/gwt/index.html>';
var ACCESS_TOKEN = '<here oAuth2 token>';
var TOKEN_TYPE = 'Bearer ';
// Helper method to set up all the required headers for making authorized calls to the YouTube API.
function generateYouTubeApiHeaders() {
return {
Authorization: TOKEN_TYPE + ACCESS_TOKEN,
'GData-Version': 2,
'X-GData-Key': 'key=' + DEV_KEY,
'X-GData-Client': 'App',
'Slug': Math.random().toString()
};
}
// Helper method to set up XML request for the video.
function generateXmlRequest(title, description, category, keywords) {
return '<?xml version="1.0"?> <entry xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" xmlns:yt="http://gdata.youtube.com/schemas/2007"> <media:group> <media:title type="plain">' + title + '</media:title> <media:description type="plain">' + description + '</media:description> <media:category scheme="http://gdata.youtube.com/schemas/2007/categories.cat">' + category + '</media:category> <media:keywords>' + keywords + '</media:keywords></media:group> </entry>';
}
// Create XHR and add event listeners
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener("progress", uploadProgress, false);
xhr.addEventListener("load", uploadComplete, false);
xhr.addEventListener("error", uploadError, false);
xhr.addEventListener("abort", uploadAbort, false);
// Specify POST target
xhr.open("POST", 'https://uploads.gdata.youtube.com/feeds/api/users/default/uploads');
// Prepare form data
var fd = new FormData();
// The order of attachments is absolutely important
fd.append('xmlrequest', generateXmlRequest('Test', 'Video', 'Autos', 'dsdfsdf, sdsdf'));
fd.append('video', document.forms.uploadNewVideoForm.file.files[0]);
// Add authentication headers
var headers = generateYouTubeApiHeaders();
for(var header in headers) {
xhr.setRequestHeader(header, headers[header]);
}
// Send request
xhr.send(fd);
I'm trying to redirect the url of my app in node.js in this way:
// response comes from the http server
response.statusCode = 302;
response.setHeader("Location", "/page");
response.end();
But the current page is mixed with the new one, it looks strange :| My solution looked totally logical, I don't really know why this happens, but if I reload the page after the redirection it works.
Anyway what's the proper way to do HTTP redirects in node?
Looks like express does it pretty much the way you have. From what I can see the differences are that they push some body content and use an absolute url.
See the express response.redirect method:
https://github.com/visionmedia/express/blob/master/lib/response.js#L335
// Support text/{plain,html} by default
if (req.accepts('html')) {
body = '<p>' + http.STATUS_CODES[status] + '. Redirecting to ' + url + '</p>';
this.header('Content-Type', 'text/html');
} else {
body = http.STATUS_CODES[status] + '. Redirecting to ' + url;
this.header('Content-Type', 'text/plain');
}
// Respond
this.statusCode = status;
this.header('Location', url);
this.end(body);
};
server = http.createServer(
function(req, res)
{
url ="http://www.google.com";
body = "Goodbye cruel localhost";
res.writeHead(301, {
'Location': url,
'Content-Length': body.length,
'Content-Type': 'text/plain' });
res.end(body);
});
Yes it should be full url in setHeader.
res.statusCode = 302;
res.setHeader('Location', 'http://' + req.headers['host'] + ('/' !== req.url)? ( '/' + req.url) : '');
res.end();
What happens if you change it to 307 instead?
This issue may also depend on the type of request you are handling. A POST request cannot be redirected using the header. For example, a first-time visitor from to your app in FB will most-likely be coming via a "signed request" POST and therefore a redirect will not work.
I'm having a problem similar to jQuery $.ajax Not Working in IE8 but it works on FireFox & Chrome, but with a different use case.
I'm using the jQuery Form plug-in to handle a file upload to an ASP.NET MVC controller, which sends the file off for parsing and processing. If an Exception is thrown, it should alert the user to the issue.
//client side code
//make an ajax call, sending the contents of the file
$("#ajaxUploadForm").ajaxSubmit({
dataType: 'json',
url: '/plan/Something/ExcelImport',
iframe: true,
beforeSend: function () {
$(".ui-dialog-buttonpane").find("#my_progress").fadeIn();
},
success: function (data, textStatus) {
output = "<center><span class='flash'>" + data.message + "</span></center>";
$("#flash_message").html(output).fadeIn('slow');
setTimeout(function () { $("#flash_message").fadeOut() }, 5000);
cleanup();
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert("XMLHttpRequest is " + XMLHttpRequest);
var contents = "";
for (prop in XMLHttpRequest) {
contents += "\na property is " + prop + " it's value is " + XMLHttpRequest[prop];
}
alert("the contents are " + contents);
alert("textStatus is " + textStatus);
alert("errorThrown is " + errorThrown);
//comes back in an HTML envelope. This should be parsed with regex, but I can't get it to work. Dirty hack
response = XMLHttpRequest.responseText.substring(XMLHttpRequest.responseText.indexOf("<body>"));
response = response.replace("<body>", "");
response = response.replace("</body>", "");
alert("There was a problem with the upload.\r\n" + response);
},
complete: function (XMLHttpRequest, textStatus) {
$(".ui-dialog-buttonpane").find("#my_progress").remove();
something_import.dialog('close');
something_import.dialog('destroy');
}
});
//server side code
public FileUploadJsonResult ExcelImport()
{
FileUploadJsonResult result = new FileUploadJsonResult();
HttpPostedFileBase hpf = Request.Files[0] as HttpPostedFileBase;
if (hpf.ContentLength == 0)
return new FileUploadJsonResult { Data = new { message = "File contained no data" } };
String fileName = Path.GetFileName(hpf.FileName);
String timeStampedFile = fileName.Insert(fileName.IndexOf('.'),"_"+DateTime.Now.ToFileTimeUtc());
string savedFileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "tempo", timeStampedFile);
hpf.SaveAs(savedFileName);
try
{
result = ProcessFile(savedFileName, Request["Id"]) as FileUploadJsonResult;
}
catch (ArgumentException e)
{
this.Response.StatusCode = 500;
this.Response.StatusDescription = System.Net.HttpStatusCode.BadRequest.ToString();
Response.Write(e.Message);
result = Json(new { message = e.Message, stackTrace = e.StackTrace }) as FileUploadJsonResult;
}
return result;
}
This works perfectly in Chrome and Firefox. In IE, the XMLHttpRequest object coming back is different:
FF:
IE:
I've been Googling around for differences between the browser implementations of XMLHttpRequest, but haven't found anything that deals specifically with this case. Stymied.
The reason this is happening is because of the iframe fallback strategy that ajaxSubmit employs. I think since the response gets posted into the iframe IE tries to figure out how to dipslay it and decides that it wants to ask you to download the response instead of just putting it in the iframe.
I came across this same situation a while ago and found an article (that I can't find now) that offered a workaround.
If you surround your json response in a textarea nobody is going to complain(IE,FF,Chrome,probably Safari) and you'll get your response parsed correctly.
E.g. if you are returning
{Id: 1, Name: 'Me'}
just return:
<textarea>{Id: 1, Name: 'Me'}</textarea>
You see now IE thinks it's html so it inserts it into the hidden iframe. Your ajaxSubmit function still gets called and parses the json correctly and then everybody's happy. :)
If you're using ASP.NET MVC you could shamelessly copy this extension method :)
public static class ControllerExtensions
{
public static ActionResult JsonSafe(this IController controller, object obj)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return new WriteResult(string.Format("<textarea>{0}</textarea>", serializer.Serialize(obj)));
}
}
The wikipedia article on XMLHttpRequest seems to give a good overview of the history behind the XMLHttpRequest. It seems Microsoft and Mozilla developed/adopted their own versions of the object and hence why you are probably seeing different properties.
Here is a link to Microsoft's implementation of the XMLHttpRequest interface members, which seem to match the properties in your alert.
Here is the a link to Mozilla's implementation of XMLHttpRequest.
So while we wait for the W3C to standardize the XMLHttpRequest you will continue to have different implementations across the browsers like you are seeing in this case.
For some added fun here is Apple's and Opera's specifications on XMLHttpRequest.