CORS error in AngularJS app - javascript

I am getting following error when I try to make a POST request from my localhost app:
XMLHttpRequest cannot load https://www.xxx..yy/json/orders. Response to preflight request doesn't pass access control check: The 'Access-Control-Allow-Origin' header contains multiple values '*, http://localhost:9000', but only one is allowed. Origin 'http://localhost:9000' is therefore not allowed access.
This is my app structure in brief:
ctrl:
.controller('myCtrl', function ($scope,$http) {
var urlBase = "https://xxx/json/";
console.log("Hello...");
$scope.startDirectTransaction = function() {
console.log("startDirectTransaction form...");
$http({method: 'POST', url: urlBase + 'orders', headers: {
'api_key': 'xxx'}
}).then(function(response){
$scope.related = response.data;
console.log("Success!");
});
};
app:
<!-- begin snippet: js hide: false -->

You are trying to POST a data from your local app to a different domain. In general this is against CORS policy.
Solution for this issue is the domain which you are trying to post the data should allow via Access-Control-Allow-Origin
Read more about CORS in https://en.wikipedia.org/wiki/Cross-origin_resource_sharing

Related

Getting json data from curl in angularJs? [duplicate]

I have created a demo using JavaScript for Flickr photo search API.
Now I am converting it to the AngularJs.
I have searched on internet and found below configuration.
Configuration:
myApp.config(function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
});
Service:
myApp.service('dataService', function($http) {
delete $http.defaults.headers.common['X-Requested-With'];
this.flickrPhotoSearch = function() {
return $http({
method: 'GET',
url: 'http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=3f807259749363aaa29c76012fa93945&tags=india&format=json&callback=?',
dataType: 'jsonp',
headers: {'Authorization': 'Token token=xxxxYYYYZzzz'}
});
}
});
Controller:
myApp.controller('flickrController', function($scope, dataService) {
$scope.data = null;
dataService.flickrPhotoSearch().then(function(dataResponse) {
$scope.data = dataResponse;
console.log($scope.data);
});
});
But still I got the same error.
Here are some links I tried:
XMLHttpRequest cannot load URL. Origin not allowed by Access-Control-Allow-Origin
http://goo.gl/JuS5B1
You don't. The server you are making the request to has to implement CORS to grant JavaScript from your website access. Your JavaScript can't grant itself permission to access another website.
I had a similar problem and for me it boiled down to adding the following HTTP headers at the response of the receiving end:
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Origin: *
You may prefer not to use the * at the end, but only the domainname of the host sending the data. Like *.example.com
But this is only feasible when you have access to the configuration of the server.
Try using the resource service to consume flickr jsonp:
var MyApp = angular.module('MyApp', ['ng', 'ngResource']);
MyApp.factory('flickrPhotos', function ($resource) {
return $resource('http://api.flickr.com/services/feeds/photos_public.gne', { format: 'json', jsoncallback: 'JSON_CALLBACK' }, { 'load': { 'method': 'JSONP' } });
});
MyApp.directive('masonry', function ($parse) {
return {
restrict: 'AC',
link: function (scope, elem, attrs) {
elem.masonry({ itemSelector: '.masonry-item', columnWidth: $parse(attrs.masonry)(scope) });
}
};
});
MyApp.directive('masonryItem', function () {
return {
restrict: 'AC',
link: function (scope, elem, attrs) {
elem.imagesLoaded(function () {
elem.parents('.masonry').masonry('reload');
});
}
};
});
MyApp.controller('MasonryCtrl', function ($scope, flickrPhotos) {
$scope.photos = flickrPhotos.load({ tags: 'dogs' });
});
Template:
<div class="masonry: 240;" ng-controller="MasonryCtrl">
<div class="masonry-item" ng-repeat="item in photos.items">
<img ng-src="{{ item.media.m }}" />
</div>
</div>
This issue occurs because of web application security model policy that is Same Origin Policy Under the policy, a web browser permits scripts contained in a first web page to access data in a second web page, but only if both web pages have the same origin. That means requester must match the exact host, protocol, and port of requesting site.
We have multiple options to over come this CORS header issue.
Using Proxy - In this solution we will run a proxy such that when request goes through the proxy it will appear like it is some same origin.
If you are using the nodeJS you can use cors-anywhere to do the proxy stuff. https://www.npmjs.com/package/cors-anywhere.
Example:-
var host = process.env.HOST || '0.0.0.0';
var port = process.env.PORT || 8080;
var cors_proxy = require('cors-anywhere');
cors_proxy.createServer({
originWhitelist: [], // Allow all origins
requireHeader: ['origin', 'x-requested-with'],
removeHeaders: ['cookie', 'cookie2']
}).listen(port, host, function() {
console.log('Running CORS Anywhere on ' + host + ':' + port);
});
JSONP - JSONP is a method for sending JSON data without worrying about cross-domain issues.It does not use the XMLHttpRequest object.It uses the <script> tag instead. https://www.w3schools.com/js/js_json_jsonp.asp
Server Side - On server side we need to enable cross-origin requests.
First we will get the Preflighted requests (OPTIONS) and we need to allow the request that is status code 200 (ok).
Preflighted requests first send an HTTP OPTIONS request header to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data. In particular, a request is preflighted if it uses methods other than GET or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.
It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)
If you are using the spring just adding the bellow code will resolves the issue.
Here I have disabled the csrf token that doesn't matter enable/disable according to your requirement.
#SpringBootApplication
public class SupplierServicesApplication {
public static void main(String[] args) {
SpringApplication.run(SupplierServicesApplication.class, args);
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
};
}
}
If you are using the spring security use below code along with above code.
#Configuration
#EnableWebSecurity
public class SupplierSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().antMatchers(HttpMethod.OPTIONS, "/**").permitAll().antMatchers("/**").authenticated().and()
.httpBasic();
}
}
I encountered a similar problem like this, problem was with the backend . I was using node server(Express). I had a get request from the frontend(angular) as shown below
onGetUser(){
return this.http.get("http://localhost:3000/user").pipe(map(
(response:Response)=>{
const user =response.json();
return user;
}
))
}
But it gave the following error
This is the backend code written using express without the headers
app.get('/user',async(req,res)=>{
const user=await getuser();
res.send(user);
})
After adding a header to the method problem was solved
app.get('/user',async(req,res)=>{
res.header("Access-Control-Allow-Origin", "*");
const user=await getuser();
res.send(user);
})
You can get more details about Enabling CORS on Node JS
This answer outlines two ways to workaround APIs that don't support CORS:
Use a CORS Proxy
Use JSONP if the API Supports it
One workaround is to use a CORS PROXY:
angular.module("app",[])
.run(function($rootScope,$http) {
var proxy = "//cors-anywhere.herokuapp.com";
var url = "http://api.ipify.org/?format=json";
$http.get(proxy +'/'+ url)
.then(function(response) {
$rootScope.response = response.data;
}).catch(function(response) {
$rootScope.response = 'ERROR: ' + response.status;
})
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="app">
Response = {{response}}
</body>
For more information, see
GitHub: CORS Anywhere
Use JSONP if the API supports it:
var url = "//api.ipify.org/";
var trust = $sce.trustAsResourceUrl(url);
$http.jsonp(trust,{params: {format:'jsonp'}})
.then(function(response) {
console.log(response);
$scope.response = response.data;
}).catch(function(response) {
console.log(response);
$scope.response = 'ERROR: ' + response.status;
})
The DEMO on PLNKR
For more information, see
AngularJS $http Service API Reference - $http.jsonp
Answered by myself.
CORS angular js + restEasy on POST
Well finally I came to this workaround:
The reason it worked with IE is because IE sends directly a POST instead of first a preflight request to ask for permission.
But I still don't know why the filter wasn't able to manage an OPTIONS request and sends by default headers that aren't described in the filter (seems like an override for that only case ... maybe a restEasy thing ...)
So I created an OPTIONS path in my rest service that rewrites the reponse and includes the headers in the response using response header
I'm still looking for the clean way to do it if anybody faced this before.
Apache/HTTPD tends to be around in most enterprises or if you're using Centos/etc at home. So, if you have that around, you can do a proxy very easily to add the necessary CORS headers.
I have a blog post on this here as I suffered with it quite a few times recently. But the important bit is just adding this to your /etc/httpd/conf/httpd.conf file and ensuring you are already doing "Listen 80":
<VirtualHost *:80>
<LocationMatch "/SomePath">
ProxyPass http://target-ip:8080/SomePath
Header add "Access-Control-Allow-Origin" "*"
</LocationMatch>
</VirtualHost>
This ensures that all requests to URLs under your-server-ip:80/SomePath route to http://target-ip:8080/SomePath (the API without CORS support) and that they return with the correct Access-Control-Allow-Origin header to allow them to work with your web-app.
Of course you can change the ports and target the whole server rather than SomePath if you like.
var result=[];
var app = angular.module('app', []);
app.controller('myCtrl', function ($scope, $http) {
var url="";// your request url
var request={};// your request parameters
var headers = {
// 'Authorization': 'Basic ' + btoa(username + ":" + password),
'Access-Control-Allow-Origin': true,
'Content-Type': 'application/json; charset=utf-8',
"X-Requested-With": "XMLHttpRequest"
}
$http.post(url, request, {
headers
})
.then(function Success(response) {
result.push(response.data);
$scope.Data = result;
},
function Error(response) {
result.push(response.data);
$scope.Data = result;
console.log(response.statusText + " " + response.status)
});
});
And also add following code in your WebApiConfig file
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
we can enable CORS in the frontend by using the ngResourse module.
But most importantly, we should have this piece of code while making the ajax
request in the controller,
$scope.weatherAPI = $resource(YOUR API,
{callback: "JSON_CALLBACK"}, {get: {method: 'JSONP'}});
$scope.weatherResult = $scope.weatherAPI.get(YOUR REQUEST DATA, if any);
Also, you must add ngResourse CDN in the script part and add as a dependency
in the app module.
<script src="https://code.angularjs.org/1.2.16/angular-resource.js"></script>
Then use "ngResourse" in the app module dependency section
var routerApp = angular.module("routerApp", ["ui.router", 'ngResource']);

Ionic using Bing Maps Proxy failing and Access-Control-Allow-Origin issue

I'm currently working on my first hybrid application and I'm having an issue with CORS. The Bing MAP API doesn't allow localhost or an actual device to call their Rest API. I've tried to reach Bing two different ways.
First attempt was with the url in my service and all urls whitelisted in the config.xml but I reached and error.
Second was to proxy the url, which is a query url. I'm not sure how to proxy a query url so I've been using a reformatted test url, but that keeps getting a 404.
Anyone know how I can fix my CORS issue? Thank you in advance
'Approach 1`
service.js
function getUserAddress() {
var uriQuery = http://dev.virtualearth.net/REST/v1/Locations/point?point=40.444009, -77.774055&includeEntityTypes=Address,Neighborhood,CountryRegion&includeNeighborhood=1&output=json&key=(removed);
return $http({
method: 'GET',
url: uriQuery,
}).then(function (response) {
console.log("location data set", response);
return getNearbyEvents(response);
}).catch(rxEventsService.onRequestFailure);
}
Config.xml
<access origin="*"/>
<allow-navigation href="*"/>
Error in Chrome
XMLHttpRequest cannot load http://dev.virtualearth.net/REST/v1/Locations/point?point=40.444009,-77.77405&include…=json&key=(remove :) ). No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access. The response had HTTP status code 404.
Approach 2
gulp.js
// webserver: Create local webserver with livereload.
gulp.task('webserver', function () {
gulp.src('./www')
.pipe(webserver({
fallback: './www/index.html',
host: '0.0.0.0',
port: 8080,
proxies: [{
source: '/_bingmaps',
target: 'http://dev.virtualearth.net/REST/v1/Locations/point?point=40.444009, -77.774055&includeEntityTypes=Address,Neighborhood,CountryRegion&includeNeighborhood=1&output=json&key=(removed)'
}]
}));
});
constants.js
(function () {
'use strict';
angular.module('rxEvents').constant('rxUrls', {
reverseGeoCoding:'/_bingmaps',
bingMapsKey:'(removed)'
});
})();
service.js
function getUserAddress() {
return $http({
method: 'GET',
url: rxUrls.reverseGeoCoding,
}).then(function (response) {
console.log("location data set", response);
return getNearbyEvents(response);
}).catch(rxEventsService.onRequestFailure);
}
Error
ionic.bundle.min.js:135 POST http://localhost:8080/_bingmaps 404 (Not Found)
The Bing Maps REST services are JSONP enabled services. Here is a blog post explaining how to access this service using various JavaScript frameworks: https://blogs.bing.com/maps/2015/03/05/accessing-the-bing-maps-rest-services-from-various-javascript-frameworks/

how to add access token in angularjs http

i am new in developing a website using angularJS as my client-side and i am trying to access my JSON thru API call with $http.get method for angular.
my issue is that my API call requires an Access Token. i always get this error whenever i try to refresh my page.
XMLHttpRequest cannot load http://unexus-api-dev-3urcgetdum.elasticbeanstalk.com/drugstores. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8888' is therefore not allowed access.
i am currently using this code to fetch my data.
myApp.controller('loginCtrl', function($scope, $http) {
$http.get("http://unexus-api-dev-3urcgetdum.elasticbeanstalk.com/drugstores")
.then(function(response) {
$scope.names = response.data.records;
});
});
how do i insert an access token on the $http.get method.
It depends on how your API get this access token. The most popular option is to just add specyfic header to your request
var req = {
method: 'POST',
url: 'http://example.com',
headers: {
'Authorization': 'access token'
},
}
$http(req).then(function(){...}, function(){...});
you can also add it globally
module.run(function($http) {
$http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';
});
or by using Angular interceptors
http://www.diwebsity.com/2015/12/17/interceptor-in-angular/
You are running into a SOP issue that is described here https://en.wikipedia.org/wiki/Same-origin_policy
You should have a look here:
Ways to circumvent the same-origin policy
Same origin policy
XMLHttpRequest Same Origin Policy

Passing OPTIONS when I should Pass PUT

I have the following configuration.
.config(config);
config.$inject = ["$httpProvider"];
function config($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common["X-Requested-With"];
//Reset headers to avoid OPTIONS request (aka preflight)
$httpProvider.defaults.headers.common = {};
$httpProvider.defaults.headers.post = {};
$httpProvider.defaults.headers.put = {};
$httpProvider.defaults.headers.patch = {};
}
As for my $resource
.factory('Order', order)
order.$inject = ['$resource', "ApiEndpoint", "UserRecord"];
function order($resource, ApiEndpoint, UserRecord) {
var id = null;
UserRecord.retrieve().then(function (user) {
id = user.user_id;
})
return $resource(ApiEndpoint.url + 'orders.json', {}, {
update: {method: 'PUT', url: ApiEndpoint.url + 'orders.json'}
});
}
Now when I call update like so
var params = { name: "new name" };
Order.update(params, {}, function (resp) {
console.log(resp);
})
My console renders No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8100' is therefore not allowed access. The response had HTTP status code 401. as an OPTIONS request. If I run a POST request, everything works fine and as intended.
When I visit the server logs it verifies I'm running an OPTIONS request. How do I fix this to run a PUT request?
You are trying to make a CORS (Cross Origin Resource Sharing) request, which means that you try to connect to a server that is not your origin. Your origin is the server that serve your application.
Due to browser security policy, every request other than GET, requires a preflight handshake (OPTIONS), in which the non origin server, describes what headers, and methods he allows someone coming from origin X.
So the only way to skip preflight, is putting the resources you are accessing on the same server from which you serve the application.

AngularJS: Cannot send POST request with appropiate CORS headers

I'm creating a web app using AngularJS. To test it, I'm running the app in a NodeJS server, using angular-seed template.
In this app, I need to send a JSON message to another host, via POST request, and get the response, so, I'm using CORS.
My request is done by implementing a service that uses AngularJS http service (I need the level of abstraction that $http provides. So, I don't use $resource).
Here, my code. Please pay attention to the fact that I modify $httpProvider to tell AngularJS to send its requests with the appropriate CORS headers.
angular.module('myapp.services', []).
// Enable AngularJS to send its requests with the appropriate CORS headers
// globally for the whole app:
config(['$httpProvider', function($httpProvider) {
$httpProvider.defaults.useXDomain = true;
/**
* Just setting useXDomain to true is not enough. AJAX request are also
* send with the X-Requested-With header, which indicate them as being
* AJAX. Removing the header is necessary, so the server is not
* rejecting the incoming request.
**/
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}
]).
factory('myService', function($http) {
return {
getResponse: function() {
var exampleCommand = JSON.stringify({"foo": "bar"});
// This really doesn't make a difference
/*
var config = {headers: {
'Access-Control-Allow-Origin':'*',
'Access-Control-Allow-Headers': 'Content-Type, Content-Length, Accept',
'Content-Type': 'application/json'
}
};
*/
//return $http.post(REMOTE_HOST, exampleCommand, config).
return $http.post(REMOTE_HOST, exampleCommand).
success(function(data, status, headers, config) {
console.log(data);
return data;
}).
error(function (data, status, headers, config) {
return {'error': status};
});
}
}
});
The problem is I can't make it work. I always get this error message:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading
the remote resource at REMOTE_HOST. This can be fixed by moving the
resource to the same domain or enabling CORS.
But if I do a simple jQuery AJAX call like this:
$.ajax(REMOTE_HOST,
{
dataType: "json",
type: "POST",
data: exampleCommand,
success: function(data) { console.log(data); },
error: function(request, textStatus, errorThrown) { console.log("error " + textStatus + ": " + errorThrown);}
});
It works fine.
So, my questions:
- How do I allow cross-site requests in an AngularJS running under NodeJS?
UPDATE: Thanks to Dayan Moreno Leon's response.
My problem is I need to add cors support to my server. I'm using NodeJS http-server for development and lighttpd for production.
- Why does the simple jQuery POST request work but AngularJS POST request doesn't?
I guess jQuery AJAX requests are cross-domain by default. Not really sure yet.
Many thanks in advance
CORS is not handled on the client but in the server you need to allow CORS on your nodejs app where your angular app is trying to POST. you can try using cors module if you are using express
https://www.npmjs.org/package/cors
other whise you need to check for the options method and return 200 as a response
http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
Why does the simple jQuery POST request work but AngularJS POST request doesn't?
jQuery uses simple requests while AngularJS uses preflighted requests
In your angular code you can add set Content-Type to application/x-www-form-urlencoded and encode your data using $.param

Categories

Resources