angular - $http first call is super slow - javascript

A controller has $http that calls an api backend on Flask. I have some basic authentication and crossdomain is set. The first time it enters the cpuListCtrl controller the $http calls takes cca. ~14sec. The next time i visited the controller in angular it takes just 23ms. But every time i press the browsers refresh, back to ~14sec. Direct api call from browser also takes just 23ms. So my question is my does it takes so long, did i miss something, or where specific should i look?
EDIT: updated the code to reflect recent changes:
var app = angular.module('RecycleApp', ['ngRoute', 'appControllers']);
app.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}
]);
app.config(['$routeProvider', function($routeProvider){
$routeProvider
.when("/cpu", {
templateUrl:'static/js/partials/cpu.html',
controller:'cpuCtrl'
})
}]);
var appControllers = angular.module('appControllers', []);
appControllers.controller('cpuCtrl', ['$scope','$http',
function($scope,$http){
$http({
url: 'http://SOME_IP/api/v1/cpus',
method: 'POST',
data: JSON.stringify({"latitude":46.1948436, "longitude":15.2000873}),
headers: {"Content-Type":"application/json"}
})
.success(function(data,status,headers,config){
console.log(data.list);
$scope.cpus = data.list;
})
.error(function(data,status,headers,config){
console.log("something went wrong.");
})
}]);
Server side:
#app.route('/api/v1/cpus', methods=["GET"])
#cross_origin(origins='*', headers=("Content-Type"))
def get_cpu_list():
result = session.query(RecycleReUseCenter)\
.options(load_only("Id", "CpuName"))\
.all()
return list_json(result)
#app.route("/api/v1/cpus", methods=["POST"])
#cross_origin(origins='*', headers=("Content-Type"))
def get_cpu_list_with_locations():
content = request.get_json(force=True)
given_latitude = content['latitude']
given_longitude = content['longitude']
result = RecycleReUseCenter.get_all_with_distance(given_latitude, given_longitude)
return list_json(result)

Do you know for sure when does the http call starts? The angular app may be stuck somewhere else, and getting to the http call only in the last second. For example - in the config you are using a "token" where do you get it from? in many angular app this is fetched from some oauth service, in a seperete call. Your slow call won't start until http is configured. After token is there, the next calls would be faster since we got the token already.
To limit some guessing you can use a proxy tool like charles - or deflect.io chrome extension to watch all the out going http calls and figure this out

I have recently had the same problem, and found that the delay oddly enough actually seems to be on the Flask end, but only happens when using an Angular app running in Chrome. This answer from the python stackexchange forum is the best one I have seen - https://stackoverflow.com/a/25835028/1521331 - it provides a 'solution' of sorts, if not an explanation for this mystery!

I was having the same problem, and none of the above worked for me. Here's what did:
Slow Requests on Local Flask Server
Effectively, certain browsers will attempt to access IPv6 sockets before IPv4. After commenting out the offending lines in /etc/hosts and restarting apache the problem was fixed.

Related

Angular JS $httpProvider interceptor -- run with no response body?

I'm using interceptors to keep a running count of all $http requests; incrementing whenever a request starts, and decrementing whenever a response comes back. The point of doing this is to allow me to show a busy spinner when any response has not yet come back without having to write the same code over and over again.
The code doing the heavy lifting is here (I've truncated the other interceptors which aren't really relevant here):
$httpProvider.interceptors.push(['$q', '$injector', function($q, $injector)
{
return {
'request': function(config)
{
httpMonitorServiceProvider.activeHttpCalls++;
return config;
},
'response': function(data)
{
httpMonitorServiceProvider.activeHttpCalls--;
return data;
}
}
}
This code works great for the most part, but some of the REST endpoints I have just return an HTTP OK status code without a response body (for POSTed "save" calls and the like where there's no need to return anything). When there's no response body the response interceptor never seems to be hit, so the counter never goes back down. If I modify the endpoints to return {} it does work.
Is there a way to intercept the responses that have no body? I can modify the REST endpoints but I consider it less than ideal to have to return empty objects everywhere to hack around this issue.

Pretty Urls in AngularJs and Laravel not working

I'm developing an application using Laravel and AngularJS. For AngularJS pretty URL , i have set $locationProvider.html5Mode(true) and it's working fine. But suppose my url is http://localhost:8000/demo and if i refresh the page, I'm getting NotFoundHttpException in compiled.php line 7693:
Here is my angular's routes.
function($routeProvider,$locationProvider) {
$locationProvider.html5Mode(true);
$routeProvider.
when('/', {
templateUrl: 'partials/index.html',
controller: 'indexController'
}).
when('/dom',{
templateUrl:'partials/dom.html',
controller:'DomController'
}).
when('/demo',{
templateUrl:'partials/demo.html',
controller:'DemoController'
});
}]);
And here's my laravel's route.
Route::get('/', function(){
return view('index');
});
I'd appreciate a little help.
Thanks!
The problem here is that the web server will pick up http://localhost:8000/demo when you refresh the page, and try to handle the request. It's not aware that you wish to use html5 routing. So it will parse the request, say "oh, I should pass this to public/index.php and be done with it". And then public/index.php will receive it and throw an error since the route doesn't exist in Laravel.
What you need to do is to make a catch all type of route in Laravel, and then let Angular's routing take over. You then render your index view on every single request. There's a great answer here on SO on how you do that in Laravel 5: How do I catch exceptions / missing pages in Laravel 5?
This is pseudo code and will not work, just to show an example:
Route::get('*', function() {
return view('index');
});
So, render the index view on every request and then let Angular handle the routing from there.

Angular Cross-Origin Request CORS failure, but node http.get() returns successfully

I am trying to access an API using AngularJS. I have checked the API functionality with the following node code. This rules out that the fault lies with
var http = require("http");
url = 'http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10';
var request = http.get(url, function (response) {
var buffer = ""
response.on("data", function (chunk) {
buffer += chunk;
});
response.on("end", function (err) {
console.log(buffer);
console.log("\n");
});
});
I run my angular app with node http-server, with the following arguments
"start": "http-server --cors -a localhost -p 8000 -c-1"
And my angular controller looks as follows
app.controller('Request', function($scope, $http){
// functional URL = http://www.w3schools.com/website/Customers_JSON.php
$scope.test = "functional";
$scope.get = function(){
$http.get('http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10',{
params: {
headers: {
//'Access-Control-Allow-Origin': '*'
'Access-Control-Request-Headers' : 'access-control-allow-origin'
}
}
})
.success(function(result) {
console.log("Success", result);
$scope.result = result;
}).error(function() {
console.log("error");
});
// the above is sending a GET request rather than an OPTIONS request
};
});
The controller can parse the w3schools URL, but it consistently returns the CORS error when passed the asterank URL.
My app avails of other remedies suggested for CORS on this site (below).
Inspecting the GET requests through Firefox shows that the headers are not being added to the GET request. But beyond that I do not know how to remedy this. Help appreciated for someone learning their way through Angular.
I have tried using $http.jsonp(). The GET request executes successfully (over the network) but the angular method returns the .error() function.
var app = angular.module('sliderDemoApp', ['ngSlider', 'ngResource']);
.config(function($httpProvider) {
//Enable cross domain calls
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
You should understand one simple thing: even though those http modules look somewhat similar, they are totally different beasts in regards to CORS.
Actually, the node.js http.get() has nothing to do with CORS. It's your server that makes a request - in the same way as your browser does when you type this URL in its location bar and command to open it. The user agents are different, yes, but the process in general is the same: a client accesses a page lying on an external server.
Now note the difference with angular's $http.get(): a client opens a page that runs a script, and this script attempts to access a page lying on an external server. In other words, this request runs in the context of another page - lying within its own domain. And unless this domain is allowed by the external server to access it in the client code, it's just not possible - that's the point of CORS, after all.
There are different workarounds: JSONP - which basically means wrapping the response into a function call - is one possible way. But it has the same key point as, well, the other workarounds - it's the external server that should allow this form of communication. Otherwise your request for JSONP is just ignored: server sends back a regular JSON, which causes an error when trying to process it as a function call.
The bottom line: unless the external server's willing to cooperate on that matter, you won't be able to use its data in your client-side application - unless you pass this data via your server (which will act like a proxy).
Asterank now allows cross origin requests to their API. You don't need to worry about these workarounds posted above any more. A simple $http.get(http://www.asterank.com/api/kepler?query={"PER":{"$lt":1.02595675,"$gt":0.67125}}&limit=10')
will work now. No headers required.I emailed them about this issue last week and they responded and configured their server to allow all origin requests.
Exact email response from Asterank : "I just enabled CORS for Asterank (ie Access-Control-Allow-Origin *). Hope this helps!"
I was having a similar issue with CORS yesterday, I worked around it using a form, hopefully this helps.
.config(function($httpProvider){
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
})
.controller('FormCtrl', function ($scope, $http) {
$scope.data = {
q: "test"//,
// z: "xxx"
};
$scope.submitForm = function () {
var filters = $scope.data;
var queryString ='';
for (i in filters){
queryString=queryString + i+"=" + filters[i] + "&";
}
$http.defaults.useXDomain = true;
var getData = {
method: 'GET',
url: 'https://YOUSEARCHDOMAIN/2013-01-01/search?' + queryString,
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
};
console.log("posting data....");
$http(getData).success(function(data, status, headers, config) {
console.log(data);
}).error(function(data, status, headers, config) {
});
}
})
<div ng-controller="FormCtrl">
<form ng-submit="submitForm()">
First names: <input type="text" name="form.firstname">
Email Address: <input type="text" ng-model="form.emailaddress">
<button>bmyutton</button>
</form>
</div>
Seems to work with the url you posted above as well..
ObjectA: 0.017DEC: 50.2413KMAG: 10.961KOI: 72.01MSTAR: 1.03PER: 0.8374903RA: 19.04529ROW: 31RPLANET: 1.38RSTAR: 1T0: 64.57439TPLANET: 1903TSTAR: 5627UPER: 0.0000015UT0: 0.00026
I should also add that in chrome you need the CORS plugin. I didn't dig into the issue quite as indepth as I should for angular. I found a base html can get around these CORS restrictions, this is just a work around until I have more time to understand the issue.
After lots of looking around. The best local solution I found for this is the npm module CORS-anywhere. Used it to create AngularJS AWS Cloudsearch Demo.

AngularJS controller is caching in Firefox and IE: how to disable?

In my angular application I have the following controller (I have deleted some methods due privacy policy):
.controller('ArticleCtrl', ['$http', '$scope', '$location', '$localStorage', '$q', '$templateCache', 'authService',
'uploaderService', 'settings',
function($http, $scope, $location, $localStorage, $q, $templateCache, authService, uploaderService, settings) {
$scope.isAuth = authService.checkAuthStatus() || false;
if ($scope.isAuth == false) {
$location.path('/signin');
}
$scope.username = $localStorage.authStatus.userName;
$scope.getCompany = function(id) {
$http.get(settings.apiBaseUri + '/app/' + id, {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache'
}
})
.success(function(response) {
$scope.company = response;
$scope.company.Email = $scope.username;
})
.error(function(data, status, headers, config) {
console.log('operation failed, status: ' + data);
$location.path('/signin');
});
$scope.$apply();
};
if ($scope.isAuth == true) {
$scope.company = $localStorage.selectedCompany;
$templateCache.removeAll();
$scope.getCompany($localStorage.selectedCompany.Id);
}
}
]);
I have spend a lot of time, but still I don't understand why does only this contoller gets cached (other controllers were made via copy-paste).
But when this method is called for the first time: all is ok, in debugger I see that it goes to server via GET method, but when I refresh the page, and then go again to this controller - in Firefox and IE I see that there are no new requests to the server. But why? Only when I refresh the page with Ctrl + F5 all is ok. But users will do not do that, I need working application...
Maybe somebody knows how to fix this issue? How to disable angularjs view and controller caching?
UPD:
I see that after update my localstorage isn't changing in IE and Firefox. Why?
Sorry, I do not directly answer the question, but what is coming seems important.
I, and other people, strongly discourage to use ngStorage right now.
Indeed, ngStorage, seems very, very handy. You just directly change the object, and voilĂ , everything works. I used this a bit, this was cool :)
But, sadly, when you try to make an advanced use, or when you take a look at the source code, you see there are several problems. This awesome "immediate localStorage object modification" is made watching stuff with the $rootScope. That's not a good idea for performance. Moreover, you probably saw that some GitHub issues are stating similar sync problems, like you do. Also, be aware that the project is now completely unmaintained. Use such a library in production is a bad idea.
So, you may give a try to another solution to make the link with the localStorage, such as Angular Locker, becoming more and more used. This will lead to some code refactoring, but you future self will thank you to not have used a problematic library.
First be sure that id parameter is correct. And second be sure that the request headers has no-cache. Probably you have request interceptor and this interceptor override the headers. Track this request in firebug for firefox.
If you see the 'no-cache' values check the server out. Maybe server could cache this.

AngularJS API call error with $http GET

I'm trying to create a simple app using Angular that will consume my API. I'm using a VM to run the code, and I access it on my computer, so to call the API from my machine I can use cURL or any other HTTP client and everything works. An example:
curl -k --user damien#email.com:password https://api.my.domain.com/v1/traveler/get
And that would return a list of travelers for example. I need to "trust" the certificate as it is not valid. So on the browser at first the call would return net::ERR_INSECURE_RESPONSE, so I'm just going to the API URL and add the exception and now I don't have this issue anymore. Then I had to add basic authentication, and it seems to work. Let's see what is my code and please let me know if you see anything wrong, I'm following this tutorial that consume an external API: http://www.toptal.com/angular-js/a-step-by-step-guide-to-your-first-angularjs-app
app.js:
angular.module('TravelerApp', [
'TravelerApp.controllers',
'TravelerApp.services'
]);
services.js:
angular.module('TravelerApp.services', [])
.factory('TravelerAPIService', function($http) {
var travelerAPI = {};
$http.defaults.headers.common.Authorization = 'Basic ABC743HFEd...=';
travelerAPI.getTravelers = function() {
return $http({
method: 'GET',
url: 'https://api.my.domain.com/v1/traveler/get'
});
}
return travelerAPI;
});
Finally, the controllers.js:
angular.module('TravelerApp.controllers', [])
.controller('travelersController', function($scope, TravelerAPIService) {
$scope.travelersList = [];
TravelerAPIService.getTravelers()
.success(function(data) {
console.log('SUCCESS');
$scope.travelersList = data;
})
.error(function(data, status) {
console.log('ERROR');
$scope.data = data || "Request failed";
$scope.status = status;
});
});
The error status code is 0, and the error data is an empty string.
Precisions:
I have the same behavior with an HTTP POST query.
I am sure :
no request have been made on the server
it's angular that don't sent the query
And finally I find the answer:
Since I (and probably you) are sending on a self signed httpS server. Chrome flag it as none safe.
I fix this issue by putting the address on my browser and manually accept the certificate.
Probably related : XMLHttpRequest to a HTTPS URL with a self-signed certificate
I would suggest to use Trusted CA Signed SSL Certificate rather then Self-Signed Certificates which would solve your problem as most browsers do not accept the self signed certificates like Google Chrome,Firefox,etc.

Categories