I am using $http to post data to server.
There are two OPTIONS requestMethod calls before making a POST request.
However, the POST request is not made sometimes.
As I am updating html on return of this call, the page hangs.
$http({
url: scope.Settings.url,
method: "POST",
data:data,
withCredentials: true
}).then(function (data, status, headers, config) {
setBusyState(false);
scope.rModel = scope.search;
scope.Results = data.data;
}, function (data, status, headers, config) {
scope.Results = [];
setBusyState(false);
});
EDIT: This does not happen always. Only a few times.
This appears to happen only in Chrome, whereas it is fine in IE
This is a known issue with AngularJS where it caches the subsequent http requests so if you have multiple http requests lined up you would sometime experience that some of the calls are not actually made.I have mainly seen this issue of aggressive caching in IE.
To overcome this issue you need to apply some sort of global settings which will prevent the http requests from getting cached.The ideal place of doing this in angular is $httpProvider.
Basically you are setting different header parameters with the appropriate values.
Related code from app.config
appConfig.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.cache = false;
//initialize get if not there
if (!$httpProvider.defaults.headers.get) {
$httpProvider.defaults.headers.get = {};
}
//disable IE ajax request caching
$httpProvider.defaults.headers.get['If-Modified-Since'] = <set a time>;
$httpProvider.defaults.headers.get['Cache-Control'] = 'no-cache';
$httpProvider.defaults.headers.get['Pragma'] = 'no-cache';
}
]);
What angular does in chrome is, it makes OPTIONS request.
These Pre-Flight OPTIONS requests are a way of asking permissions for the actual request, before making the actual request.
So, as a work around, adding headers to the request solves the problem.
$http({
url: scope.Settings.url,
method: "POST",
data: data,
headers: {
'Content-Type': 'application/json'
},
withCredentials: true
}).then(function(data, status, headers, config) {
setBusyState(false);
scope.rModel = scope.search;
scope.Results = data.data;
}, function(data, status, headers, config) {
scope.Results = [];
setBusyState(false);
});
Related
cookie does show in browser however cannot be accessed using $cookie.get('io'). What am I missing. I also tried $timeout with 5 seconds delay. I tried to see in headers() but this token does not show there.
Code:
$http({
url: 'http://localhost:8081/api/v1/login',
method: 'POST',
data: $httpParamSerializerJQLike({
username: username,
password: password,
REQUEST_TYPE: requestType
}), // Make sure to inject the service you choose to the controller
headers: {
'Content-Type': 'application/x-www-form-urlencoded' // Note the appropriate header
}
}).success(function (data, status, headers, config) {
//10 seconds delay
$timeout( function(){
var favoriteCookie = $cookies.get('io');
alert(favoriteCookie);
}, 5000 );
//time
var time = 0;
//timer callback
var timer = function() {
if( time < 5000 ) {
time += 1000;
$timeout(timer, 1000);
}
}
//run!!
$timeout(timer, 1000);
//console.log(response.headers('set-cookie'));
callback(response = { success: true });
}).error(function (data, status, headers, config) {
callback(response = { success: false });
});
Please check that the cookie you are trying to get is not tagged as httpOnly.
When you tag a cookie with the HttpOnly flag, it tells the browser
that this particular cookie should only be accessed by the server. Any
attempt to access the cookie from client script is strictly forbidden.
Of course, this presumes you have: A modern web browser. A browser
that actually implements HttpOnly correctly.
it was autogenerated cookie. the cookie which i was trying to access did not appear in the browser. I had to make some code modifications in angularjs to get the cookie into browser. I had to include a parameter "withCredentials:true," in the http request. As soon as I did it my cookie appeared in the browser. Now my http request look like this.
$http({
url: 'http:localhost/login',
method: 'POST',
data: $httpParamSerializerJQLike({
username: username,
password: password,
REQUEST_TYPE: requestType
}), // Make sure to inject the service you choose to the controller
withCredentials:true,
headers: {
'Content-Type': 'application/x-www-form-urlencoded;
}
}).success(function (data, status, headers, config) {
callback(response = { success: true });
}).error(function (data, status, headers, config) {
callback(response = { success: false });
});
}
In my AngularJS app I am sending HTTP GET request as below.
MyService.HttpReq("testUrl", "GET", null);
HttpReq Method is defined in a service and implemented as below:
this.HttpReq = function(URL, method, payload)
{
$http({
url: URL,
method: method,
cache: false,
data: postData,
headers: {
'Content-Type': 'application/json',
}
}).success(function(response)
{
console.log("Success: "+JSON.stringify(response));
}).error(function(data, status)
{
console.error("Error");
});
}
First of all is this the right way of sending HTTP request in AngularJS?
The problem that I am facing is, some times I get cached data as response and HTTP request is not hitting the server. what can be the issue?
UPDATE
As per the comment and answer I have updated my HTTP request code as below, but still getting same issue.
this.HttpReq = function(URL, method, payload)
{
$http({
url: URL,
method: method,
cache: false,
data: payload,
headers: {
'Content-Type': 'application/json',
'Cache-Control' : 'no-cache'
}
}).
then(
function(response)
{
var data = response.data;
console.log("Success: "+JSON.stringify(data));
},
function(response)
{
var data = response.data || "Request failed";
var status = response.status;
console.error("Error: "+JSON.stringify(data));
}
);
}
IE Browsers will catch ajax get requests even if we add cache control headers to the response. Only way i found to solve the issue is to add some random parameter to the request. Please make sure the api have no problem even if you send extra parameters
MyService.HttpReq("testUrl?ts=" + Date.now(), "GET", null);
Just add cache: false attribute to config object.
https://docs.angularjs.org/api/ng/service/$http#caching
Also you can add header: 'Cache-Control' : 'no-cache'
I am trying to get a $http REST GET call working in my Appgyver project working but nothing I do seems to come right, always returns an error.
Please note the angular app will be running on mobile devices eventually and then connect to my remote web service.
I've double checked that my custom API is working and returning data correctly in a number of ways, namely:
hard coded cUrl request running from sh files in terminal - Returns data and correct 200 code
Tested the API end points in both POSTMAN and Firefox's SOA client.
Putting in my test end point of http://somesite.com/quote-and-buy-performance/druidapi/taxonomy_term returns data as below:
[{"tid":"1","vid":"2","name":"ACME Ltd.","description":"","format":"filtered_html","weight":"0","parent":"0","uri":"http://somesite.com/quote-and-buy-performance/druidapi/taxonomy_term/1"},{"tid":"2","vid":"2","name":"ABC Films LTD","description":"","format":"filtered_html","weight":"0","parent":"0","uri":"http://somesite.com/quote-and-buy-performance/druidapi/taxonomy_term/2"}]
Even a simple CSRF Token request gives me errors.
Could someone possibly point out where I am going wrong here, the Appgyver site is badly documented and I have tried the Angular RESTful sample which my code below is based upon from https://docs.angularjs.org/api/ng/service/$http and https://docs.angularjs.org/api/ng/service/$http#setting-http-headers
Please note the code below is basically Angular.js using Javascript syntax (as opposed to Coffeescript), logging output follows the code
angular
.module('main')
.controller('LoginController', function($scope, supersonic, $http) {
$scope.navbarTitle = "Settings";
$scope.stoken = "Response goes here";
$scope.processLogin = function(){
var csrfToken;
steroids.logger.log("START CALL: processLogin");
// $form_login_email_address = $scope.login_email;
// $form_login_password = $scope.login_password;
$local_get = "http://somesite.com/quote-and-buy-performance/services/session/token";
$hal_get_taxterm_index = "http://somesite.com/quote-and-buy-performance/druidapi/taxonomy_term";
// $http.defaults.headers.common.contentType('application/json');
var req = {
method: 'GET',
url: $hal_get_taxterm_index,
headers: {
'Content-Type': 'application/json'
}
}
$http(req)
.success(function(data, status, headers) {
steroids.logger.log("Inside http.get() success");
}).error(function(data, status, headers){
steroids.logger.log("Inside http.get() WITH ERROR");
steroids.logger.log('data: ' + data);
steroids.logger.log('status: ' + status);
}).then(function(data, status, headers){
steroids.logger.log("Inside http.get() then");
});
steroids.logger.log("END CALL: processLogin");
}
});
Logging output from calls to steroids.logger.log
View Time Level Message
main#login 16:01:55.219 info "Inside http.get() WITH ERROR"
main#login 16:01:55.219 info "data: null"
main#login 16:01:55.219 info "status: 0"
main#login 16:01:55.64 info "END CALL: processLogin"
main#login 16:01:55.64 info "START CALL: processLogin"
Here's what I would do:
Separate out your http call into a service. This is a pretty standard way to modularize your code in angular:
angular.module('main').factory("SomeService", function($http) {
return {
get: function() {
$http({
url: "http://somesite.com/quote-and-buy-performance/druidapi/taxonomy_term",
method: "GET",
headers: {
"Content-Type": "application/json"
}
}).success(function(data, status, headers, config) {
console.log("Success!");
console.log(data);
}).error(function(data, status, headers, config) {
console.log("Error!");
console.log(status);
console.log(data);
});
}
}
})
Then to use this in your controller, just include it in your controller declaration and call get like you would a normal method:
angular.module('main').controller('LoginController', function($scope, supersonic, SomeService) {
$scope.navbarTitle = "Settings";
$scope.stoken = "Response goes here";
$scope.processLogin = function(){
var csrfToken;
steroids.logger.log("START CALL: processLogin");
SomeService.get();
steroids.logger.log("END CALL: processLogin");
}
})
Do this and then comment back with your results and we can work from there.
If your angular's app is within a certain domain, then HTTP request must be made within the same domain.
In your case, you are trying a cross domain request (a request on another domain). You must then make a cross domain request.
You can see this question.
The author uses $http.jsonp() to send cross domain requests. There migth be another way to do it.
Here is my service:
home.factory("homeService", function ($http, $q) {
var service =
{
getAssets: function () {
var deferred = $q.defer();
var response = $http({
method: "post",
dataType: "json",
data: '',
headers: {
'Content-Type': "application/json"
},
url: "http://localhost/myWeb/services/reports_ws.asmx/getData",
});
response.success(function (data) {
deferred.resolve(data);
});
response.error(function (data) {
alert('Error');
});
// Return the promise to the controller
return deferred.promise;
},
}
return service;
I am getting 500 error from the server when I use application/json for the content. using plain/text works fine and data is returned, but in an xml format although the server sends data back in json format. I have tested it in Chrome, everything works fine. I also noticed that Chrome sends request using "application/x-www-form-urlencoded" for content-type. I tried it too, but still got data in xml. Please help.
Thanks
keep trying with the following:
header: { "Content-Type" : "application/x-www-form-urlencoded"}
Please notice that this applies only for the header of the request, not the response. The response depends on your backend (server side).
Several ways are available to return JSON data in the response depending of the type of server you are using.
So, this has been a huge struggle for us.
We have a web API .net MVC4 back-end. We are using angular for client-side. We have a page that has some JSON that we receive data from. When we make a GET to this page we receive data. As soon as we add custom headers to the call the GET turns into OPTIONS and we get a 200, with no response. We are doing a couple things like creating a BASE64 code on "login" storing it as a cookie and trying to add that to the GET headers. the thing is we have stripped out all of the unnecessary code and we are still at the same problem. Even with authorization turned off for the data. Here is the GET code:
myApp.factory("projectDataService", function ($http, $location, $cookieStore) {
var token = "";
token = $cookieStore.get('token');
return {
getProject: function (successcb) {
$http({ method: "GET", url: "http://dev.projnik.com/api/project", headers: { 'Authorization': 'Basic ' + token } }).
success(function (data, status, headers, config) {
successcb(data);
}).
error(function (data, status, headers, config) {
console.log(data, status, headers, config);
});
},
save: function (project) {
$http({ method: "POST", url: "http://dev.projnik.com/api/project", data: $.param(project) }).
success(function (data, status) {
if (status == '201') {
$location.path('/all');
}
})
}
};
});
And the app.js:
var myApp = angular.module('Project', ['ngResource', 'ngCookies']);
myApp.config(function($routeProvider){
$routeProvider.
when('/new', {templateUrl:'templates/new.html', controller:'EditProjectController'}).
when('/mobile', {templateUrl:'templates/mobile.html', controller:'ProjectController'}).
when('/it', {templateUrl:'templates/it.html', controller:'ProjectController'}).
when('/writing', {templateUrl:'templates/writing.html', controller:'ProjectController'}).
when('/all', { templateUrl: 'templates/all.html' }).
when('/cookie', { templateUrl: 'partials/cookiecontrollerhtml.html' }).
when('/login', { templateUrl: 'partials/_login.html' }).
otherwise({ redirectTo: '/all' });
});
myApp.config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);
Again, without adding headers attribute to the call, everything works (obviously we get a 401 with Authorization turned on in the API). We are willing to pay for an answer at this point.
We are exposing our actual domains here, and that is fine. If someone goes to www.projnik.com and clicks the login link on the top and enter shane, password for username,password they would receive the cookie and it routes the user back to the #/all page where they would GET the data, though it doesn't work.
PS: I have tried to ad withCredentials = true; to the call and I get the same result.
If you are accessing API in dev.projnik.com from a web page in www.projnik.com, in a browser like Chrome, CORS comes into play. If you make a GET without any custom headers, it is a simple CORS request and I assume you have settings in web.config that sends Access-Control-Allow-Origin header and that makes it work. Once you add a custom header, it is no longer a simple CORS and it becomes pre-flighted CORS with browser making an OPTIONS request. The response to this OPTIONS request must send the correct CORS headers for the browser to make the subsequent GET. To enable CORS, check this out. BTW, in IIS there is a default handler that answers OPTIONS call that you might need to remove for the message handler in Web API to respond to OPTIONS.
I am working with Shane on this - the block of code on the server is:
public void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
//These headers are handling the "pre-flight" OPTIONS call sent by the browser
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
I believe this takes care of the situation. But the problem is still there.