All $http requests are returning -1 - angularjs

I am working on an app using ionic. Just today, all of my $http requests started failing by returning -1 status codes. This is happening when I run with ionic serve, ionic run browser and ionic emulate ios.
These $http requests are not necessarily remote, either. It's failing to load the HTML files inside of www/template. Any help with debugging would be greatly appreciated!
Some more details:
When running ionic serve, it loads index.html just fine, which loads my app.js. That in turn sets up an HTTP interceptor and loads the states using $stateProvider:
angular.module('starter', ['ionic', 'ngCordova', 'ionic.service.core', 'starter.controllers', 'setup.controllers', 'settings.controllers', 'history.controllers', 'graph.controller'])
...
.config(function ($stateProvider, $urlRouterProvider, $httpProvider, $analyticsProvider) {
...
$httpProvider.interceptors.push(['$q', '$location', function ($q, $location) {
return {
'request': function (config) {
// Setup authorization token...
return config;
},
'responseError': function (response) {
if (response.status === 401 || response.status === 403) {
$location.path('/login');
}
return $q.reject(response);
}
};
}]);
...
$stateProvider.state('login', {
cache: false,
url: '/login',
templateUrl: 'templates/login.html',
controller: 'LoginCtrl'
})
// setup an abstract state for the tabs directive
.state('tab', {
url: '/tab',
abstract: true,
cache: false,
controller: 'TabCtrl',
templateUrl: 'templates/tabs.html'
})
...
My browser's javascript console is filled with these errors:
ionic.bundle.js:25000 GET http://localhost:8100/templates/tabs.html net::ERR_EMPTY_RESPONSE(anonymous function) # ionic.bundle.js:25000sendReq # ionic.bundle.js:24793serverRequest # ionic.bundle.js:24503processQueue # ionic.bundle.js:29127(anonymous function) # ionic.bundle.js:29143$eval # ionic.bundle.js:30395$digest # ionic.bundle.js:30211$apply # ionic.bundle.js:30503(anonymous function) # ionic.bundle.js:32332completeOutstandingRequest # ionic.bundle.js:19194(anonymous function) # ionic.bundle.js:19470
ionic.bundle.js:25000 GET http://localhost:8100/templates/login.html net::ERR_EMPTY_RESPONSE(anonymous function) # ionic.bundle.js:25000sendReq # ionic.bundle.js:24793serverRequest # ionic.bundle.js:24503processQueue # ionic.bundle.js:29127(anonymous function) # ionic.bundle.js:29143$eval # ionic.bundle.js:30395$digest # ionic.bundle.js:30211$apply # ionic.bundle.js:30503(anonymous function) # ionic.bundle.js:32332completeOutstandingRequest # ionic.bundle.js:19194(anonymous function) # ionic.bundle.js:19470
When I drop a breakpoint in the interceptor, it intercepts the requests for these local HTML files and shows the response status code as -1.
UPDATE 1:
It keeps getting stranger... if I clear out the local storage, it works... once. I use local storage to store the logged in user account, so when I clear the storage and refresh, it successfully loads the pages. After I log in, all the requests stop working.

I spent a lot of time during investigation this issue and finally find out the problem.
In my case I have interceptor which adds Bearer Authorization data to each request, all worked amazing until this Bearer had small size, however I made design mistake and added a large amount of data to it after that problems started.
After minimizing Bearer request size all work as expected.

Related

Angular Route doesn't work (no error)

I am new to Angular and I need help with UI Router. I need to load mylink.html after clicking on link. Here is my code:
var app = angular.module('hollywood', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.html5Mode({enabled: true, requireBase: false});
$stateProvider.state('mylink', {
templateUrl: 'mylink.html'
});
})
<a ui-sref="mylink">My Link</a>
<article ui-view></article>
What am I doing wrong? There is no error in console, except error after click:
XMLHttpRequest cannot load .... Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.
The thing is file is local and I don't think I can set up CORS in these case.
https://jsfiddle.net/2q61mcp9/
Try using this code
var app = angular.module('hollywood', ['ui.router']);
app.config(function($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
$stateProvider.state('mylink', {
url: '/my-link',
templateUrl: 'mylink.html' // give absolute url like src/views/mylink/html
});
})
You missed to add url in state object
#Damian Are you serving your angular app via some kind of server (python ,node etc), or are you simply running the app via file system(Directly via open with browser option) in browser ?
If you are directly running it you are most likely to get this CORS issue as browsers dont allow resource sharing via file system for security issues.
My code is correct. I've deleted 'url' and run it on server. It work's.

Angular URL routing issue

So I needed to change my URL so that google analytics could track it. Google analytics wouldn't accept it with the "/#/" (hash) in the link. That said, I used Angular's locationProvider and revised my app routing with:
(function() {
'use strict';
angular
.module('mbapp')
.config(routerConfig);
/** #ngInject */
function routerConfig($stateProvider, $urlRouterProvider, $locationProvider) {
$stateProvider
.state('home', {
url: '/',
templateUrl: 'app/main/main.html',
controller: 'MainController',
controllerAs: 'main'
});
$stateProvider
.state('steps', {
url: '/steps',
templateUrl: 'app/steps/steps.html',
controller: 'StepsController',
controllerAs: 'steps'
});
// use the HTML5 History API
$locationProvider.html5Mode(true);
$urlRouterProvider.otherwise('/');
}
})();
My URL is fine and changes it to http://website.com/steps rather than http://website.com/#/steps. However, now, if a user refreshes (f5) the link it then throw a 404 error and not sure why. Additionally, it seems that somehow this gets injected as the URL when the refresh is called "http://website/steps#/steps".
Any ideas on this?
Thanks much.
The problem is probably on the server side. You have to configure your server so it responds to every request with your html file. For example in express:
var app = require('express')();
app.configure(function(){
// static - all our js, css, images, etc go into the assets path
app.use('/assets', express.static('/assets'));
app.get('/api/users/:id', function(req, res){
// return data for user....
});
// This route deals enables HTML5Mode by forwarding missing files to the index.html
app.all('/*', function(req, res) {
res.sendfile('index.html');
});
});
When you reload the page, the request goes to the server side of your application, and it tries to resolve the url but it probably can't, because those routes only exists on the client side of your application.
Also it is a good idea to prefix every server side route with an /api route prefix, so you can easily distinguish between client side and server side routes.

difference between RestangularProvider and RestangularConfigurer

I wanted to add an interceptor to my module.
Here is the intial state:
app.config(function ($stateProvider, $urlRouterProvider,RestangularProvider) {
RestangularProvider.setBaseUrl('/app/services');
});
I modified with this:
app.config(function ($stateProvider, $urlRouterProvider, RestangularProvider, RestangularConfigurer) {
RestangularProvider.setBaseUrl('/app/services');
RestangularConfigurer.addFullRequestInterceptor(function (element, operation, route, url, headers, params, httpConfig) {
if (operation === 'get'){
console.log("RestangularProvider: call to get");
params.ts= new Date();
}
return {
element: element,
headers: headers,
params: params,
httpConfig: httpConfig
};
});
});
However, I add an error:
Error: [$injector:unpr] Unknown provider: RestangularConfigurer
So I replaced RestangularConfigurer by RestangularProvider.
But I do not clearly understand how that works, and what's happening behind the scenes.
Could you explain me that ?
First of all there is no RestangularConfigurer module. You have only Restangular and its provider RestangularProvider.
Let's start with angularjs documentation for providers.
Please esspecially read Provider Recipe as I do not duplicate it again here.
As a summary RestangularProvider is just a recipe how Restangular api should be build as you decide it in config module there is no Restangular api yet, but you have your recipe.
On the other hand Restangular will be bootstraped after your main module bootstraped, so in config there is actually no Restangular module yet.
If you still insist using Restangular instead its provider you can use it in module#run instead of module#config.

angularjs pretty url is not working

My problem is url is not working without # . Here is my code :
angular.module('Hiren', ['ngRoute'])
.config(function ($routeProvider, $locationProvider) {
$routeProvider
.when('/', {
templateUrl: 'partials/login.html',
controller: 'login'
})
.when('/redirect', {
templateUrl: 'partials/postLogin.html',
controller: 'postLogin'
});
$locationProvider.html5Mode(true);
});
When I try to browse the url example.com/redirect , it gives me 404 , but using hash ( example.com/#redirect) its perfectly working .
If you're getting a 404 in HTML5 mode you need to configure your server to serve your Angular application (usually index.html or app.html) when a 404 happens on the server. You don't mention what you're using for a server so I can't give specific instructions on how to do that. This is more a server configuration issue than an Angular one.
Edit now that server is known:
import SimpleHTTPServer, SocketServer
import urlparse, os
PORT = 3000
class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
def do_GET(self):
# Parse query data to find out what was requested
parsedParams = urlparse.urlparse(self.path)
# See if the file requested exists
if os.access('.' + os.sep + parsedParams.path, os.R_OK):
# File exists, serve it up
SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self);
else:
# redirect to index.html
self.send_response(302)
self.send_header('Content-Type', 'text/html')
self.send_header('location', '/index.html')
self.end_headers()
Handler = MyHandler
httpd = SocketServer.TCPServer(("", PORT), Handler)
print "serving at port", PORT
httpd.serve_forever()
Referenced SO answer.

How to load data synchronously in AngularJS application

Now I know that because of the way javascript executes it is recommended that you run all remote requests as async instead of sync. While I agree with that 99% of the time, sometimes you do want to run remote request as a sync instead of a async. For example, loading session data is something I would want to do synchronically as I don't want any views to render until that data is loaded. This plunker shows the issue with loading session data asynchronically (NOTE: I am using $timeout to simulate what would happen with an async call):
http://plnkr.co/edit/bzE1XP23MkE5YKWxRYrn?p=preview
The data property does not load anything because the data is not available when it tries to get it and data2 does only because the data is available when it tries to get it. Now in this case I could just put the session variable on the scope and be done with it but that is not always the case.
Is there a better way to do sync remote calls in an angular application other than using jQuery's .ajax() method (trying to depend on jQuery as little as possible)?
If you want the session data to be loaded prior to a controller being loaded, you should included it as as resolve parameter (assuming you are using the $routeProvider).
For example:
angular.module('mymodule', ['ngResource'])
/* here's our session resource. we can call Session.get() to retrieve it. */
.factory('Session', ['$resource', function($resource) {
return $resource('/api/session.json');
}])
/* here's our controller + route definition. */
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/foo', {
controller: 'MyCtrl',
templateUrl: '/templates/foo.html',
/* the controller will not be loaded until the items
* below are all resolved! */
resolve: {
session: ['$q', 'Session', function($q, Session) {
var d = $q.defer();
Session.get(function(session) {
/* session returned successfully */
d.resolve(session);
}, function(err) {
/* session failed to load */
d.reject(err);
});
return d.promise;
}]
}
});
}])
.controller('MyCtrl', ['$scope', 'session', function($scope, session) {
/* 'session' here is the key we passed to resolve above.
* It will already be loaded and resolved before this function is called */
$scope.session = session;
}]);
Angular is hardcoded to make the requests async. To do it synchronously would take other code, whether custom or from some other library. Here is line 9269 from angular 1.0.7:
xhr.open(method, url, true);
The third param makes it asynchronous.
I would take a step back and think about how you are doing things. You could provide some loading indicator while your async request is going and easily control the loading of a view in the success callback so that it doesn't appear until the data is loaded.
A better solution is to add a response interceptor:
checkAuth = ($q, $location) ->
success = (response) ->
response
error = (response) ->
errorCode = response.status
$location.path '/login' if errorCode is 403 or errorCode is 401
# $q.reject response - no need because we are redirecting before any other promises in the chain will resolve (were breaking our future promises)
(promise) ->
promise.then success, error
$httpProvider.responseInterceptors.push checkAuth
And in your $routeProvider, or $stateProvider in my case:
.state 'user',
templateUrl: 'assets/views/user/partials/user.html'
resolve:
credentials: (checkLogIn) ->
checkLogIn.get().$promise
When checkLogIn.get()'s promise is rejected (the error handler is fired), assuming it's a 401 or 403 response (unauthenticated or unauthorized), the promise chain will be broken and the user will be "redirected" to /login.
With this method, any error calls will be channelled into the interceptor, instead of handling errors on a route-by-route basis.

Resources