I want to pull posts from a users Facebook wall.
The following code snippet works, but it never terminates:
var https = require('https');
facebookWall = function(user) {
var options = {
host: 'graph.facebook.com',
port: 443,
path: '/me/home?access_token=' + user.facebook_token + '&since=' + encodeURIComponent(user.facebook_timestamp),
method: 'GET',
headers: {
'Connection':'keep-alive'
}
};
var req = https.request(options)
.on('response', function(response) {
var body = '';
response.on('data', function(data) {
body += data;
try {
var wallPosts = JSON.parse(body);
console.log("user " + user.id + " has " + wallPosts.data.length + " new items on their wall");
}
catch (e) {
//console.log("waiting for more data chunks...");
}
})
});
req.end();
req.on('error', function(e) {
console.error(e);
});
}
I think it is caused by the 'Connection':'keep-alive' header. When I replace it with 'Connection':'close' the script will terminate when all data has been retrieved from facebook.
I'm hoping to be able to use the keep-alive header to prevent having to create a new SSL connection for each request. I have thousands of requests and with the keep-alive header, it completes in just a few seconds, as opposed to a few minutes without the keep-alive header.
Does anyone know how to accomplish this? I'm fairly new to Node.JS, so if I'm missing something obvious, I apologize.
It's because keep-alive is not yet implemented for https/tls/ssl
in node 4.x and I believe for 6.x too. That's why in node websocket-server
it doesn't work as well, see https://github.com/nephics/node-websocket-server/commit/3a732bff6aabe694834d87086a7718be7c0ce138
I notice you're using https. Depends on what version of node you're using, but there is a known issue with the end event right now.
https://github.com/joyent/node/issues/728
You have to do the following:
1) Put response.on('end', function() { ... do the output ... }); for the https.request
Don't output data in the response.on('data', ...);
2) Use Connection:keep-alive , "close" will cause very poor performance issue. I have done lot of testing and I can confirm this.
Other than that:
3) In your options , set the agent, and set agent.maxSockets to a larger number if you need concurrency. default is only 5.
4) You should consider to make your own routine to handle https.request timeout. (please go to github/joyent and search for it. basically use setTimeout to emit a timeout error).
Related
I having been facing this error in custom functions excel Add-in, where I'm trying to call an external service inside a custom function. It works fine for a GET request such as this:
function stockPrice(ticker) {
var url = "https://api.iextrading.com/1.0/stock/" + ticker + "/price";
return fetch(url)
.then(function(response) {
return response.text();
})
.then(function(text) {
return parseFloat(text);
});
}
CustomFunctionMappings.STOCKPRICE = stockPrice;
Taken from https://learn.microsoft.com/en-us/office/dev/add-ins/excel/excel-tutorial-custom-functions#create-a-custom-function-that-requests-data-from-the-web
But gives an exception for a POST request like this:
function stockPrice(ticker) {
var url = "https://westcentralus.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment";
return fetch(url, {
method: 'POST',
headers: {
'Ocp-Apim-Subscription-Key': key,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(body))
.then(function(response) {
return response.json();
})
.then(function(response) {
return response.somevalue;
})
.catch(e => {
console.error("Caught exception");
return JSON.stringify(e);
});
}
The above is just a sample to have an idea, of how I'm calling my service. I have tried it with 2-3 different services, and I figured out that after running fetch, the code goes to catch block, and the error value that is returned in the excel is an empty object '{}'. Since there are no ways to debug custom functions on windows, and since there is no specific error description, I'm unable to figure out the issue. I have also added my service domain to App Domain list in manifest file but still no effect.
I am not sure that particular API accepts POST requests, so you maybe running into that.
Debugging in Windows is still being worked on but you can use Excel online and F12tools to debug.
If you are on Windows, you can console.log statements in conjunction with the Runtime logging:
https://learn.microsoft.com/en-us/office/dev/add-ins/excel/custom-functions-best-practices#troubleshooting
Hope that helps and we will update this when debugging is ready on for custom functions on windows desktop.
I am trying to add an option label and option value to an optionset field(new_contractserving) found on an entity called new_servingtime. Not sure if I am doing this correctly, but the server throws a 400 Bad request, what's the issue?!
var entity = {
"new_contractserving": String(OptionValue),
"new_contractserving#OData.Community.Display.V1.FormattedValue": String(OptionText)
};
var reqJSON = new XMLHttpRequest();
reqJSON.open("POST", url + "/api/data/v8.2/new_servingtimes", false);
reqJSON.setRequestHeader("OData-MaxVersion", "4.0");
reqJSON.setRequestHeader("OData-Version", "4.0");
reqJSON.setRequestHeader("Accept", "application/json");
reqJSON.setRequestHeader("Content-Type", "application/json; charset=utf-8");
reqJSON.onreadystatechange = function () {
if (this.readyState === 4) {
reqJSON.onreadystatechange = null;
if (this.status === 204) {
var uri = this.getResponseHeader("OData-EntityId");
var regExp = /\(([^)]+)\)/;
var matches = regExp.exec(uri);
var newEntityId = matches[1];
} else {
Xrm.Utility.alertDialog(this.statusText + ": Third Request!");
return;
}
}
};
reqJSON.send(entity);
HTTP 400 means bad data. If it was "URI not found" it would have been a HTTP 404
HTTP 400 on a POST usually means, your request (requestbody) failed some validation on the server side or it did not confine to the format which server is expecting
You should be using InsertOptionValue Action to add new option to the existing picklist attribute in an entity.
CRM REST Builder is the best choice to compose such requests & test.
The request you have written can be used to set attribute value in a record, but still it’s incomplete. Read this blog to understand how you can execute webapi action.
I am running an automation script. We have a scenario where Java makes a callback REST call to UI. Below is the code where am doing httpGet to that URL. I want to know when the response comes. If it comes how to know that. I searched a lot I din't find a clear answer anywhere. Please give some hints!
http.get(siteUrl, function(response) {
var bodyString = '';
response.setEncoding('utf8');
response.on("data", function(chunk) {
bodyString += chunk;
});
response.on('end', function() {
defer.fulfill({
statusCode: response.statusCode,
bodyString: bodyString
});
});
}).on('error', function(e) {
defer.reject("Got http.get error: " + e.message);
});
//If we are sure that response has come, then extract it
httpGet("http://testurl").then(function(result) {
//alert('inside test automation');
console.log(result);
});
You can use the response detail whether success or fail with "response code", there are lots of way using interface as callback, using methods by checking response code, lots of network library available - volley, okhttp rest client etc...
help : response code detail
if(response.statusCode == 200) {
// do success work read response etc...
// you can call methods what you want if success happen
} else {
// you can check other status code too..
// call methods if api get fail.
}
Hope this would help
good luck.
I'm in the process of building a new AngularJS frontend for a Drupal 7 website. This is using the Services module with session-based authentication, across two domains using CORS. I am able to authenticate with Drupal, retrieve the user object and session data, and then get the CSRF token from the services module. What I'm having trouble with is setting all this up in the header so that subsequent requests are authenticated. I understand the overall concept but am new to both AngularJS and preventing CSRF attacks.
From what I have gathered reading about this set-up with AngularJS and RubyOnRails, there can be inconsistencies between platforms concerning what the token is named and how it is processed. There also seems to be a number of suggestions on how to set this token in the header. However, I'm having trouble in finding a solid example of how to get these platforms speaking the same language.
The only thing I'm doing with my $httpProvider in app.js is:
delete $httpProvider.defaults.headers.common['X-Requested-With'];
The login controller, in controller.js:
.controller('LoginCtrl', ['$scope', '$http', '$cookies', 'SessionService', function($scope, $http, $cookies, SessionService) {
$scope.login = function(user) {
//set login url and variables
var url = 'http://mywebsite.com/service/default/user/login.json';
var postDataString = 'name=' + encodeURIComponent(user.username) + '&pass=' + encodeURIComponent(user.password);
$http({
method: 'POST',
url: url,
data : postDataString,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function (data, status, headers, config) {
var sessId = data.sessid;
var sessName = data.session_name;
$cookies[sessName] = sessId;
var xsrfUrl = 'http://mywebsite.com/services/session/token';
$http({
method: 'GET',
url: xsrfUrl
}).success(function (data, status, headers, config) {
$cookies["XSRF-TOKEN"] = data;
SessionService.setUserAuthenticated(true);
}).error(function (data, status, headers, config) {
console.log('error loading xsrf/csrf');
});
}).error(function (data, status, headers, config) {
if(data) {
console.log(data);
var msgText = data.join("\n");
alert(msgText);
} else {
alert('Unable to login');
}
});
};
The solution has to do with how the cookies need to be set and then passed through subsequent requests. Attempts to set them manually did not go well but the solution was simpler than I expected. Each $http call needs to set the options:
withCredentials: true
Another change I made was to use the term CSRF instead of XSRF, to be consistent with Drupal. I didn't use any built-in AngularJS CSRF functionality.
addItem: function(data)
{
return $http.post('api/programs/'+$stateParams.id+'/workouts', {item:data},{
headers:
{
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-CSRF-Token': $('meta[name="xxtkn"]').attr('content')
}
});
}
since it has been a year of this topic! not sure still encountering the same problem but for the ones who comes to search for answers here is how i handle it!
Pay attention the headers{} part i define a new header and call it X-CSRF-Token and grab value from the DOM of (serverside) generated html or php. It is not a good practise to also request the csrf token from the server.Cuz attacker could somehow request that as well. Since you save it as a cookie. Attacker can steal the cookie! No need to save it in a cookie! send the token with header and read it in the serverside to match it!
and for multitab of a same page issue. I use the same token thruout the whole session.
Only regenerate on login, logout and change of major site or user settings.
There is a great library callse ng-drupal-7-services. If you use this in you project it solves authentication / reauthentication and file / node creation aut of the box and you can fokuse on the importent stuff in your project.
So Authentication is there solved like this:
function login(loginData) {
//UserResource ahndles all requeste of the services 3.x user resource.
return UserResource
.login(loginData)
.success(function (responseData, status, headers, config) {
setAuthenticationHeaders(responseData.token);
setLastConnectTime(Date.now());
setConnectionState((responseData.user.uid === 0)?false:true)
setCookies(responseData.sessid, responseData.session_name);
setCurrentUser(responseData.user);
AuthenticationChannel.pubLoginConfirmed(responseData);
})
.error(function (responseError, status, headers, config) {
AuthenticationChannel.pubLoginFailed(responseError);
});
};
(function() {
'use strict';
AuthenticationHttpInterceptor.$inject = [ '$injector'];
function AuthenticationHttpInterceptor($injector) {
var intercepter = {
request : doRequestCongiguration,
};
return intercepter;
function doRequestCongiguration (config) {
var tokenHeaders = null;
// Need to manually retrieve dependencies with $injector.invoke
// because Authentication depends on $http, which doesn't exist during the
// configuration phase (when we are setting up interceptors).
// Using $injector.invoke ensures that we are provided with the
// dependencies after they have been created.
$injector.invoke(['AuthenticationService', function (AuthenticationService) {
tokenHeaders = AuthenticationService.getAuthenticationHeaders();
}]);
//add headers_______________________
//add Authorisation and X-CSRF-TOKEN if given
if (tokenHeaders) {
angular.extend(config.headers, tokenHeaders);
}
//add flags_________________________________________________
//add withCredentials to every request
//needed because we send cookies in our request headers
config.withCredentials = true;
return config;
};
There is also some kind of kitchen sink for this project here: Drupal-API-Explorer
Yes, each platform has their own convention in naming their tokens.
Here is a small lib put together hoping to make it easy to use with different platforms. This will allow you to use set names and could be used across all requests. It also works for cross-domain requests.
https://github.com/pasupulaphani/angular-csrf-cross-domain
On the client, in the browser, I have this code:
this.socket.on('initial', function(data) {
console.log(data);
});
On the server I have:
socket.sockets.on('connection', function(client){
console.log('client connected');
});
My question is: how can I detect the URL where the request came from? For example if the first closure was running on "/posts/view/1", I want to be able to detect it inside of the second closure.
You could send this data back to the server. A little hand-wavey on the details, but how about something like:
On the client:
this.socket.on('initial', function(data) {
// do whatever with data
var my_location = get_page_location_with_javascript(); // or whatever
this.socket.emit('phone_home', my_location);
});
On the server:
this.sockets.on('phone_home', function(url) {
console.log("The URL was " + url);
});