I am trying to get response from GetFeatureInfo of sample WMS. But getting
"Unable to load http://ogi.state.ok.us/geoserver/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&SRS=EPSG:4326&BBOX=-104.5005,32.7501,-94.01,37.20&WIDTH=800&HEIGHT=300&LAYERS=ogi:okcounties&QUERY_LAYERS=ogi:okcounties&STYLES=&X=550&Y=105& status: 0"
var httpurl = "http://ogi.state.ok.us/geoserver/wms?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetFeatureInfo&SRS=EPSG:4326&BBOX=-104.5005,32.7501,-94.01,37.20&WIDTH=800&HEIGHT=300&LAYERS=ogi:okcounties&QUERY_LAYERS=ogi:okcounties&STYLES=&X=550&Y=105&";
try {
require(["dojo/request"], function (request) {
var promise = request(httpurl);
promise.response.then(
function (response) {
var kk = response;
},
function (error) {
var kk = error;
}
);
});
} catch (ex) {
alert(ex.message);
}
I see a couple potential issues:
Based on the request documentation, I think you should call .then() directly on your promise. Lke this:
promise.then(...);
on this line: var kk = data; ... you're using the variable data but you should be using response.
You may be getting a CORS issue - is your code running on the same domain as that URL? If not, and the website owner does not want to enable CORS for your domain, you may need to run a CORS proxy (google it)
Related
I'm capturing the HTTP requests in a Firefox Add-on SDK extension. I need to get the DOM window associated with the request. However, I'm getting an NS_NOINTERFACE error.
Here is my code:
var httpRequestObserver = {
observe: function (subject, topic, data) {
var httpRequest = subject.QueryInterface(Ci.nsIHttpChannel);
var requestUrl = subject.URI.host;
var domWin;
var assWindow;
console.log('URL: ', requestUrl);
try {
domWin = httpRequest.notificationCallbacks.getInterface(Ci.nsIDOMWindow);
assWindow = httpChannel.notificationCallbacks.getInterface(Ci.nsILoadContext)
.associatedWindow;
console.log(domWin);
} catch (e) {
console.log(e);
}
// console.log('TAB: ', tabsLib.getTabForWindow(domWin.top));
var hostName = wn.domWindow.getBrowser().selectedBrowser.contentWindow.location.host;
console.log('HOST: ', hostName);
},
get observerService() {
return Cc['#mozilla.org/observer-service;1'].getService(Ci.nsIObserverService);
},
register: function () {
this.observerService.addObserver(this, 'http-on-modify-request', false);
},
unregister: function () {
this.observerService.removeObserver(this, 'http-on-modify-request');
}
};
httpRequestObserver.register();
I've tried both nsIDOMWindow and nsILoadContext, but NS_NOINTERFACE error always appears on an attempt to get the window object.
I have finally managed to get the data I need via
httpRequest.notificationCallbacks.getInterface(Ci.nsILoadContext).topFrameElement
For example, to get url of the document which started the request, I used
httpRequest.notificationCallbacks.getInterface(Ci.nsILoadContext).topFrameElement._documentURI.href
Since you already found how to get the <browser> from the request you can do the following to get back to SDK APIs:
let browser = ....topFrameElement
let xulTab = browser.ownerDocument.defaultView.gBrowser.getTabForBrowser(browser)
let sdkTab = modelFor(xulTab)
modelFor() is documented in the tabs module.
Ran into another road block today, on my path of writing a desktop chrome app for logging users project time.
What i am trying to do (and failing) is use the Apps Script API to access a google sheet that retains the information (project numbers) that i want to populate a drop down in my Chrome App UI.
Update:
I have reworded this as to get to the point and be a little clear on what my issue is.
What i cant seem to achieve is calling the Apps script function from my chrome app. I have read this Execution API but still cant seem to make the coloration. for some reasons i keep getting the "Uncaught ReferenceError: gapi is not defined" in my console.
What i have managed to do is have both the Apps Script and the Chrome App under the same project name in the Developers Console. not sure if its needed but thought it might help with only 1 Oauth2 request.
Is there something my thick head is missing?
Any help or ideas would be much appreciated.
This is my manifest.json
{
"manifest_version": 2,
"name": "TimeSheet",
"description": "Small and easy desktop app for entering time spent on project files",
"version": "0.1.0",
"icons": {
"128": "icon_128.png"
},
"app": {
"background": {
"scripts": ["background.js"]
}
},
"permissions": [
"identity",
"app.window.alwaysOnTop"
],
"oauth2": {
"client_id": "clientid.apps.googleusercontent.com",
"scopes": [
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/spreadsheets"
]
},
"key": "very long string"
}
This is the bit of Oauth2 code running in my main.js
//This code confirms Oauth2 for access to google drive and related files
window.onload = function(){
document.querySelector("#Oauth2").addEventListener("click", function(){
chrome.identity.getAuthToken({"interactive": true}, function(token){
console.log(token);
});
});
};
// ID of the script to call. Acquire this from the Apps Script editor,
// under Publish > Deploy as API executable.
var scriptId = "blah";
// Create execution request.
var request = {
'function': 'getProjectNumbers',
};
// Make the request.
var op = gapi.client.request({
'root': 'https://script.googleapis.com',
'path': 'v1/scripts/' + scriptId + ':run',
'method': 'POST',
'body': request
});
// Log the results of the request.
op.execute(function(resp) {
if (resp.error && resp.error.status) {
// The API encountered a problem before the script started executing.
console.log('Error calling API: ' + JSON.stringify(resp, null, 2));
} else if (resp.error) {
// The API executed, but the script returned an error.
var error = resp.error.details[0];
console.log('Script error! Message: ' + error.errorMessage);
if (error.scriptStackTraceElements) {
// There may not be a stacktrace if the script didn't start executing.
console.log('Script error stacktrace:');
for (var i = 0; i < error.scriptStackTraceElements.length; i++) {
var trace = error.scriptStackTraceElements[i];
console.log('\t' + trace.function + ':' + trace.lineNumber);
}
}
} else {
// Here, the function returns an array of strings.
var projectNumbers = resp.response.result;
console.log('Project numbers in spreadsheet:');
projectNumbers.forEach(function(name){
console.log(name);
});
}
});
And this is the apps script code:
var projectDatabaseKey = 'blah'; //Project Database Sheet spreadsheet key
var pprojectDatabaseSheet = 'Project Database'; //Project Database Sheet spreadsheet sheet
//Function to revieve data of project numbers for drop down list
function getProjectNumbers() {
return SpreadsheetApp
.openById(projectDatabaseKey).getSheetByName(projectDatabaseSheet)
.getRange("A2:A" + (SpreadsheetApp.openById(projectDatabaseKey).getSheetByName(projectDatabaseSheet).getLastRow()))
.getValues();
}
I am just really unsure how to use the Oauth2 token and how to apply it to the apps script.
UPDATE
Ok i have tried to call an apps script in a different manor, What i am trying today is using the gapi-chrome-apps.js library to do the oauth2 work.
Now my problem is i get this error, that could be a range of things i am guessing:
POST https://www.googleapis.com/v1/scripts/blahblah:run 404 ()
gapi.client.request # VM80 gapi-chrome-apps.js:105
getSheetsList # gapiCallback.js:17
(anonymous function) # gapiCallback.js:49
callbackWrapper # VM80 gapi-chrome-apps.js:68
target.(anonymous function) # extensions::SafeBuiltins:19
safeCallbackApply # extensions::sendRequest:21
handleResponse # extensions::sendRequest:72
And this Error, that comes from the gapi-chrome-apps.js script:
Uncaught SyntaxError: Unexpected token N in JSON at position 0
Really not sure what is causing this, here is my updated code:
//get listof sheets in spreadsheet
function getSheetsList(){
var scriptId = "blahblah";
// Initialize parameters for function call.
var sheetId = "blahblah";
// Create execution request.
var requests = {
'function': 'getSheetNames',
'parameters': [sheetId],
'devMode': true // Optional.
};
// Make the request.
gapi.client.request({
'root': 'https://script.googleapis.com',
'path': 'v1/scripts/' + scriptId + ':run',
'method': 'POST',
'body': requests,
'callback': printSheetsList
});
}
// Log the results of the request.
function printSheetsList(resp) {
if (resp.error && resp.error.status) {
// The API encountered a problem before the script started executing.
console.log('Error calling API: ' + JSON.stringify(resp, null, 2));
} else if (resp.error) {
// The API executed, but the script returned an error.
var error = resp.error.details[0];
console.log('Script error! Message: ' + error.errorMessage);
} else {
// Here, the function returns an array of strings.
var sheetNames = resp.response.result;
console.log('Sheet names in spreadsheet:');
sheetNames.forEach(function(name){
console.log(name);
});
}
}
//Prompts the user for authorization and then proceeds to
function authorize(params, callback) {
gapi.auth.authorize(params, function(accessToken) {
if (!accessToken) {
console.log("Error getting authorization");
} else {
callback();
}
});
}
function gapiIsLoaded() {
var params = { 'immediate': true };
if (!(chrome && chrome.app && chrome.app.runtime)) {
params.scope = "https://www.googleapis.com/auth/drive";
params.client_id = "blahblah";
gapi.auth.init(authorize.bind(null, params, getSheetsList));
} else {
authorize(params, getSheetsList);
}
}
Using traditional GAPI will not work, since it dynamically loads more external scripts and Apps are not allowed to do that.
One possible solution is to run GAPI code in a sandboxed page, which can overcome the remote code restriction. This, however, is cumbersome as you'll need to pass data back and forth using postMessage.
Another way is to try and use Google-provided library gapi-chrome-apps.js, that works in Chrome apps (and uses chrome.identity to manage OAuth) - but please note this comment:
This library is likely not suitable for use without additional modifications.
According to your post, you are simply not defining gapi. You can load it like this
jQuery.getScript( "https://apis.google.com/js/api.js", onApiLoad );
where onApiLoad is the function you would like to call when the gapi is loaded.
For your code, I would wrap the following code in a function like this:
function onApiLoad() {
// Make the request.
var op = gapi.client.request({
'root': 'https://script.googleapis.com',
'path': 'v1/scripts/' + scriptId + ':run',
'method': 'POST',
'body': request
});
// Log the results of the request.
op.execute(function(resp) {
if (resp.error && resp.error.status) {
// The API encountered a problem before the script started executing.
console.log('Error calling API: ' + JSON.stringify(resp, null, 2));
} else if (resp.error) {
// The API executed, but the script returned an error.
var error = resp.error.details[0];
console.log('Script error! Message: ' + error.errorMessage);
if (error.scriptStackTraceElements) {
// There may not be a stacktrace if the script didn't start executing.
console.log('Script error stacktrace:');
for (var i = 0; i < error.scriptStackTraceElements.length; i++) {
var trace = error.scriptStackTraceElements[i];
console.log('\t' + trace.function + ':' + trace.lineNumber);
}
}
} else {
// Here, the function returns an array of strings.
var projectNumbers = resp.response.result;
console.log('Project numbers in spreadsheet:');
projectNumbers.forEach(function(name){
console.log(name);
});
}
});
}
Edit: no jQuery, only pure JS
Thanks to the second answer in this post, the below code is a pure JS implementation of $.getScript(). It includes a callback, so the code snippet below should work, assuming you wrap your code in a function as described above.
function getScript(source, callback) {
var script = document.createElement('script');
var prior = document.getElementsByTagName('script')[0];
script.async = 1;
prior.parentNode.insertBefore(script, prior);
script.onload = script.onreadystatechange = function( _, isAbort ) {
if(isAbort || !script.readyState || /loaded|complete/.test(script.readyState) ) {
script.onload = script.onreadystatechange = null;
script = undefined;
if(!isAbort) { if(callback) callback(); }
}
};
script.src = source;
}
getScript("https://apis.google.com/js/api.js", onApiLoad);
I'm using AJAX/JQuery to call a WCF service. I have some .NET try/catch error-handling on the service-side that checks to see if the user has timed out, and if they have then I pass back a JSON-converted message which I then parse out on the client-end using parseJSON and use it to re-direct the user back a login page.
This is all working great, but I just got a different type of error returned from the service that WASN'T in JSON format (it was XML) so the error-handling function got a javascript error on the client side when it tried to parse the reply. The error was in the jquery.min.js file, and was an 'Invalid character' error.
My question (finally), is there a better way to handle that reply if I can't always rely on it being JSON? In .NET we have a tryParse method available that would work great here, but as far as I know JQuery/Javascript has no such feature. If it can't parse the reply, it throws a JS error.
Here is where the custom JSON exception is thrown:
private HttpSessionState GetUserSession()
{
HttpSessionState session = HttpContext.Current.Session;
try
{
// This is a method we created that checks if user has timed out and throws the exception if so.
SessionBuilder.Create(session, HttpContext.Current.Request, HttpContext.Current.Response);
}
catch (SessionTimeOutException e)
{
throw new WebFaultException<SessionTimeOutException>(new SessionTimeOutException(e.Message), System.Net.HttpStatusCode.BadRequest);
}
return session;
}
And here is the client-side code that handles errors in my AJAX request:
error: function (HttpRequest)
{
// This is the line that gets the exception because the responseText is a standard .NET XML error, not my custom JSON error.
var parsedReply = $.parseJSON(HttpRequest.responseText);
if (parsedReply.ClassName === "SessionTimeOutException")
{
var url = "../timeout.asp?" + parsedReply.Message;
window.location.href = url;
}
}
JavaScript has try { ... } catch(ex) { ... } also.
error: function (HttpRequest)
{
var parsedReply;
try {
parseReply = $.parseJSON(HttpRequest.responseText);
if (parsedReply.ClassName === "SessionTimeOutException")
{
var url = "../timeout.asp?" + parsedReply.Message;
window.location.href = url;
}
} catch(ex) {
parsedReply = HttpRequest.responseText;
//Do something else
}
}
I have a controller.js file that I am trying to get data from my feed-service.js file. FEEDLY_USER_ID and FEEDLY_ACCESS_TOKEN are accessible and defined in a separate config.js file.
controller.js:
$scope.feedlyGlobalAll = FeedService.getGlobalAll();
feed-service.js:
var request = require('request');
var globalOptions = {
url: 'https://cloud.feedly.com/v3/streams/contents?streamId=user/' + FEEDLY_USER_ID + '/category/global.all',
auth: {
'bearer': FEEDLY_ACCESS_TOKEN
}
};
service.getGlobalAll = function(){
request.get(globalOptions, function(error, response, body){
if(!error && response.statusCode == 200){
service.globalAll = JSON.parse(body);
return service.globalAll;
}
// error code here //
})
}
I'm using an npm package called "request" to make the GET because I couldn't get https.get() work. This Feedly API call requires the URL, my user ID, and an access token passed in the header.
I've been reading and apparently I'm supposed to use callbacks or promises, but I can't get either of them to work. With http.get(), I can utilize promises by http.get().then(yada yada), which works for the forecast.io call I'm making elsewhere. The request module apparently doesn't allow .then(). I typically run into TypeError and .then() is not a function.
When I tried doing https.get(), here is the code I was using. I was never able to acquire a successful response.
var url = {
url: 'https://cloud.feedly.com/v3/streams/contents?streamId=user/' + FEEDLY_USER_ID + '/category/global.all',
'headers': {
'Authorization': 'Bearer ' + FEEDLY_ACCESS_TOKEN
}
};
https = require('https');
https.get(url).then(yada yada)
I tried numerous things in the var url for the https.get call. I tried with and without quotes, I tried just auth: bearer token as it works with the request module, but wasn't able to get it to work.
Solution to this issue would either be:
Callback from feed-service to controller using existing request module code.
Figuring out the correct way to form the url for the https.get request and then I can utilize its promise function.
Use a promise inside your request callback:
service.getGlobalAll = function() {
return $q(function(resolve, reject) {
request.get(globalOptions, function(error, response, body){
if(!error && response.statusCode == 200){
service.globalAll = JSON.parse(body);
resolve(service.globalAll);
} else {
reject();
}
});
});
};
$q (angular's promise api) can be injected as a dependency in your service. The above code will return a promise that will resolve when your library's ajax call returns, so you can access it with .then().
OK, I must be dense since I cannot find anywhere how to get the error status codes when using Node.JS http.get or http.request.
My code:
var deferred = $q.defer();
var req = https.get(options, function(response) {
var str = '';
response.on('data', function(chunk) {
str += chunk;
});
response.on('end', function() {
console.log("[evfService] Got user info: " + str);
deferred.resolve(str);
});
});
req.on('error', function(e) {
deferred.reject(e);
});
In that "req.on" bit, what I want is the http status code (i.e. 401, 403, etc.). What I get is a semi-useless error object that does not give me the code or any reference to the response object.
I have tried intercepting in the function(response) callback, but when there is a 404, it never gets called.
Thanks!
Your callback gets called regardless of the response status code from the server, so within your callback, check response.statusCode. That is, a 4xx status code isn't an error at the level you're working at; the server responded, it's just that the server responded by saying the resource wasn't available (etc.)
This is in the documentation but characteristically vague. Here's the example they give, with a comment pointing to the relevant bit:
var https = require('https');
https.get('https://encrypted.google.com/', function(res) {
console.log("statusCode: ", res.statusCode); // <======= Here's the status code
console.log("headers: ", res.headers);
res.on('data', function(d) {
process.stdout.write(d);
});
}).on('error', function(e) {
console.error(e);
});
If you try that with (say) an unknown resource, you'll see statusCode: 404.
So for what you're doing, you may want something like this:
var deferred = $q.defer();
var req = https.get(options, function (response) {
var str = "";
if (response.statusCode < 200 || response.statusCode > 299) { // (I don"t know if the 3xx responses come here, if so you"ll want to handle them appropriately
response.on("data", function() { } ); // ¹
deferred.reject(/*...with appropriate information, including statusCode if you like...*/);
}
else {
response.on("data", function (chunk) {
str += chunk;
});
response.on("end", function () {
console.log("[evfService] Got user info: " + str);
deferred.resolve(str);
});
}
});
req.on("error", function (e) {
deferred.reject(/*...with appropriate information, but status code is irrelevant [there isn"t one]...*/);
});
¹ The empty data event handler in the branch handling non-OK status codes is there because of this note in the documentation:
...if a 'response' event handler is added, then the data from the response object must be consumed, either by calling response.read() whenever there is a 'readable' event, or by adding a 'data' handler, or by calling the .resume() method. Until the data is consumed, the 'end' event will not fire. Also, until the data is read it will consume memory that can eventually lead to a 'process out of memory' error.
Since we're passing a function to https.get, we're hooking the 'response' event, which suggests we need to do one of those things (in this case, I've added a do-nothing data handler). Thanks to Nicolas2bert for pointing that out!.
An error code 400 response is not considered an error by node.js.
Try response.statusCode in this:
request.on('response', function (response) {});
Here's a very small example how to get the error code. Just change the https to http and create an error:
var https = require('https')
var username = "monajalal3"
var request = https.get("https://teamtreehouse.com/" + username +".json", function (response) {
console.log(response.statusCode);
});
request.on("error", function (error) {
console.error(error.status);
});