Enable CORS Post Request from AngularJS to Jersey - java

I'm attempting to post a JSON document from an AngularJS app to a Jersey REST service. The request fails, informing me that:
XMLHttpRequest cannot load http://localhost:8080/my.rest.service/api/order/addOrder. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
Jersey REST Post Function
I have enabled (what I believe to be) the appropriate headers: Access-Control-Allow-Origin and Access-Control-Allow-Methods on the response, as seen in the method below:
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#Path("/addOrder")
public Response addOrder(DBObject dbobject) {
DB db = mongo.getDB("staffing");
DBCollection col = db.getCollection("orders");
col.insert(dbobject);
ObjectId id = (ObjectId)dbobject.get("_id");
return Response.ok()
.entity(id)
.header("Access-Control-Allow-Origin","*")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
.allow("OPTIONS")
.build();
}
Angular JS Controller
I've declared the app and configured the $httpProvider with all of the settings suggested in similar Stack Overflow questions:
var staffingApp = angular.module('myApp', ['ngRoute', 'ui.bootstrap']);
myApp.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.common["Accept"] = "application/json";
$httpProvider.defaults.headers.common["Content-Type"] = "application/json";
}]);
I've also created this controller to open a modal and handle the form:
var modalCtrl = function($scope, $modal, $log, $http, $location) {
$scope.order = {
activityTitle : null,
anticipatedAwardDate : null,
component : null,
activityGroup : null,
activityCategory : null,
activityDescription : null
};
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'addOrder.html',
windowClass: 'modal',
controller: modalInstanceCtrl,
resolve: {
order : function () {
return $scope.order;
}
}
});
modalInstance.result.then(function (oid) {
$log.info("Form Submitted, headed to page...");
$location.path("/orders/" + oid);
}, function() {
$log.info("Form Cancelled")
});
};
};
var modalInstanceCtrl = function ($scope, $modalInstance, $log, $http, order) {
$scope.order = order,
$scope.ok = function () {
$log.log('Submitting user info');
$log.log(order);
$log.log('And now in JSON....');
$log.log(JSON.stringify(order));
$http.post('http://localhost:8080/my.rest.service/api/order/addOrder', JSON.stringify(order)).success(function(data){
$log.log("here's the data:\n");
$log.log(data);
$modalInstance.close(data._id.$oid)
});
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
};
myApp.controller('modalCtrl', modalCtrl);
To no avail, I've tried:
removing .allow("OPTIONS") from the response headers.
removing the $httpProvider configuration from the application
changed the $httpProvider configuration to call myApp.config(function ($httpProvider) {...}), passing the function itself rather than the array.
Get requests work with the same configuration:
#GET
#Path("/listall/")
#Produces(MediaType.APPLICATION_JSON)
public Response listAll(){
DB db = mongo.getDB("staffing");
DBCollection col = db.getCollection("orders");
List<DBObject> res = col.find().limit(200).toArray();
return Response.ok()
.entity(res.toString())
.header("Access-Control-Allow-Origin","*")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
.allow("OPTIONS")
.build();
}
with this controller that works fine:
myApp.controller('orderListCtrl', function ($scope, $http){
$http.get('http://localhost:8080/my.rest.service/api/order/listall').success(function(data) {
for (var i = 0; i < data.length; i++) {
if (data[i].description.length > 200) {
data[i].shortDesc = data[i].description.substring(0,196) + "...";
} else {
data[i].shortDesc = data[i].description;
}
};
$scope.orders = data;
});
});
Update #1:
I've tried the same request on a same origin basis, essentially serving the Angular application alongside the REST service from locahost:8080. This configuration worked, but required a slight change and some general clean up in my code, which I've edited above.
The Post still fails as a CORS request, however so I'm still looking for the missing piece in this configuration.
Update #2:
I've investigated the headers of the working request as they're delivered to the browser and compared them with the non-working request.
The working get request returns the following headers with its response:
The non-working post request returns headers with its response, but is missing the Access-Control-Allow-Origin header:
I believe this has now become an issue of the headers being stripped off of the response prior to returning it to the client, which would then cause the browser to fail the request.
Update #3:
Submitting a test POST request to the same URL from Chrome's REST Console extension returns the appropriate response headers, as seen in the screencap below.
At this point, I can't determine what's removing the headers between Jersey and my Angular client, but I'm fairly confident that's the culprit.

The problem turned out to be inadequate handling of the OPTIONS request sent in pre-flight prior to the POST request with the proper cross origin headers.
I was able to resolve the issue by downloading and implementing the CORS filter found at this page: http://software.dzhuvinov.com/cors-filter-installation.html.
If you're experiencing a similar problem, follow the instructions and test to see that your OPTIONS request is no longer failing, and is immediately followed by your successful request.

Best way is to add Jersey Response filter which will add the CORS headers for all the methods. You don't have to change your webservices implementation.
I will explain for Jersey 2.x
1) First add a ResponseFilter as shown below
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
public class CorsResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
responseContext.getHeaders().add("Access-Control-Allow-Origin","*");
responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
}
}
2) then in the web.xml , in the jersey servlet declaration add the below
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>YOUR PACKAGE.CorsResponseFilter</param-value>
</init-param>

I had faced similar CORS error while calling my Restful service (implemented in java - Jersey) from angularjs. To fix it I added Access-Control-Allow-Origin: * in response header. I added below :
response.addHeader("Access-Control-Allow-Origin", "*");
For more information you can check - http://enable-cors.org/server.html
CORS error occurs typically when your angularjs code (web project) and webserivce code (server side project) are on different IP and port no.
Your webservice implementation looks correct. So just to check, try running them on localhost on same port (eg. 8080). It should work there if all code is correct.
In order to run them separately try adding Access-Control-Allow-Origin: * in webservice implementation as shown above.
Hope this helps.

Actually, you have other solution that does not need a filter. Adding the Access-Control-Allow-* headers to the GET request, is not enough, you have to create an OPTIONS endpoint to allow browsers do the pre-flight request, i.e.:
#OPTIONS
public Response corsMyResource(#HeaderParam("Access-Control-Request-Headers") String requestH) {
ResponseBuilder rb = Response.ok();
return buildResponse(rb, requestH);
}
see https://kdecherf.com/blog/2011/06/19/java-jersey-a-cors-compliant-rest-api/ for reference.

Related

Cosuming a java webservice json into Angular4

I made a java webservice with Jersey and Javax.ws.rs, and at my controller a made a method that returns a list of json objects. This is the method >
#Path("chamados")
public class ChamadoController {
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/")
public List<Chamado> listChamados(){
Chamado c1 = new Chamado();
c1.setId(50);
c1.setAssunto("assunto1");
c1.setMensagem("oi");
c1.setStatus(Status.NOVO);
Chamado c2 = new Chamado();
c2.setId(20);
c2.setAssunto("assunto2");
c2.setMensagem("oi2");
c2.setStatus(Status.FECHADO);
List<Chamado> list1 = new ArrayList<Chamado>();
list1.add(c1);
list1.add(c2);
return list1;
}
}
The output when I run the project with apache and access /rest/chamados/ is this >
[{"id":50,"assunto":"assunto1","mensagem":"oi","status":"NOVO"},
{"id":20,"assunto":"assunto2","mensagem":"oi2","status":"FECHADO"}]
My issue is when i try to print it at my angular4 project, i never done this before so im kinda lost, this how im tryng to print it >
export class AppComponent{
data: any = {};
constructor(private http: Http){
this.getData();
this.getImages();
}
getData(){
return this.http.get(this.apiURI).map((res: Response) => res.json())
}
getImages(){
this.getData().subscribe(data => {
console.log(data);
})
}
private apiURI = 'http://localhost:8080/aprendendo-java-backend/rest/chamados/';
}
This is the error I get when trying to console.log >
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/aprendendo-java-backend/rest/chamados/. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
Any tips on whats wrong or how should I be doing this?
Thanks in advance
One possible solution:
look at this documentation: Enabling Cross Origin Requests for a RESTful Web Service
Add an annotation #CrossOrigin to your java method like this:
#Path("chamados")
#CrossOrigin(origins = "http://localhost:9000")
public class ChamadoController {
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/")
public List<Chamado> listChamados(){
Chamado c1 = new Chamado();
c1.setId(50);
c1.setAssunto("assunto1");
c1.setMensagem("oi");
c1.setStatus(Status.NOVO);
Chamado c2 = new Chamado();
c2.setId(20);
c2.setAssunto("assunto2");
c2.setMensagem("oi2");
c2.setStatus(Status.FECHADO);
List<Chamado> list1 = new ArrayList<Chamado>();
list1.add(c1);
list1.add(c2);
return list1;
}
}
Change the port number (9000 port in my example) to what ever port you use in your Nodejs server or what ever web server port you have that serves your web pages.
Using Google Chrome try installing this "Allow-Control-Allow-Origin" extension.
enter link description here
Try maybe help.
This extension causes it to fool your webservice, not reading the request as a request from localhost.
Easiest way:
you can also use JsonP, you need to wrap the JSON in a function and then use the Jsonp facility in Angular.
https://angular.io/api/http/Jsonp
Same issue i had faced. i was changed #CrossOrigin(origins = "http://localhost:4200") into #CrossOrigin then its working
Thanks for the awnsers guys, i was able to do it by adding this to the end of getMethod >>
return Response
.status(200)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization")
.header("Access-Control-Allow-Credentials", "true")
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
.header("Access-Control-Max-Age", "1209600")
.entity(list1)
.build();
Not sure if this is safe tho....anyone know?

Unable to extract response body in Angular.js [duplicate]

I'm attempting to post a JSON document from an AngularJS app to a Jersey REST service. The request fails, informing me that:
XMLHttpRequest cannot load http://localhost:8080/my.rest.service/api/order/addOrder. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.
Jersey REST Post Function
I have enabled (what I believe to be) the appropriate headers: Access-Control-Allow-Origin and Access-Control-Allow-Methods on the response, as seen in the method below:
#POST
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
#Path("/addOrder")
public Response addOrder(DBObject dbobject) {
DB db = mongo.getDB("staffing");
DBCollection col = db.getCollection("orders");
col.insert(dbobject);
ObjectId id = (ObjectId)dbobject.get("_id");
return Response.ok()
.entity(id)
.header("Access-Control-Allow-Origin","*")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
.allow("OPTIONS")
.build();
}
Angular JS Controller
I've declared the app and configured the $httpProvider with all of the settings suggested in similar Stack Overflow questions:
var staffingApp = angular.module('myApp', ['ngRoute', 'ui.bootstrap']);
myApp.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
$httpProvider.defaults.headers.common["Accept"] = "application/json";
$httpProvider.defaults.headers.common["Content-Type"] = "application/json";
}]);
I've also created this controller to open a modal and handle the form:
var modalCtrl = function($scope, $modal, $log, $http, $location) {
$scope.order = {
activityTitle : null,
anticipatedAwardDate : null,
component : null,
activityGroup : null,
activityCategory : null,
activityDescription : null
};
$scope.open = function () {
var modalInstance = $modal.open({
templateUrl: 'addOrder.html',
windowClass: 'modal',
controller: modalInstanceCtrl,
resolve: {
order : function () {
return $scope.order;
}
}
});
modalInstance.result.then(function (oid) {
$log.info("Form Submitted, headed to page...");
$location.path("/orders/" + oid);
}, function() {
$log.info("Form Cancelled")
});
};
};
var modalInstanceCtrl = function ($scope, $modalInstance, $log, $http, order) {
$scope.order = order,
$scope.ok = function () {
$log.log('Submitting user info');
$log.log(order);
$log.log('And now in JSON....');
$log.log(JSON.stringify(order));
$http.post('http://localhost:8080/my.rest.service/api/order/addOrder', JSON.stringify(order)).success(function(data){
$log.log("here's the data:\n");
$log.log(data);
$modalInstance.close(data._id.$oid)
});
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
};
myApp.controller('modalCtrl', modalCtrl);
To no avail, I've tried:
removing .allow("OPTIONS") from the response headers.
removing the $httpProvider configuration from the application
changed the $httpProvider configuration to call myApp.config(function ($httpProvider) {...}), passing the function itself rather than the array.
Get requests work with the same configuration:
#GET
#Path("/listall/")
#Produces(MediaType.APPLICATION_JSON)
public Response listAll(){
DB db = mongo.getDB("staffing");
DBCollection col = db.getCollection("orders");
List<DBObject> res = col.find().limit(200).toArray();
return Response.ok()
.entity(res.toString())
.header("Access-Control-Allow-Origin","*")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
.allow("OPTIONS")
.build();
}
with this controller that works fine:
myApp.controller('orderListCtrl', function ($scope, $http){
$http.get('http://localhost:8080/my.rest.service/api/order/listall').success(function(data) {
for (var i = 0; i < data.length; i++) {
if (data[i].description.length > 200) {
data[i].shortDesc = data[i].description.substring(0,196) + "...";
} else {
data[i].shortDesc = data[i].description;
}
};
$scope.orders = data;
});
});
Update #1:
I've tried the same request on a same origin basis, essentially serving the Angular application alongside the REST service from locahost:8080. This configuration worked, but required a slight change and some general clean up in my code, which I've edited above.
The Post still fails as a CORS request, however so I'm still looking for the missing piece in this configuration.
Update #2:
I've investigated the headers of the working request as they're delivered to the browser and compared them with the non-working request.
The working get request returns the following headers with its response:
The non-working post request returns headers with its response, but is missing the Access-Control-Allow-Origin header:
I believe this has now become an issue of the headers being stripped off of the response prior to returning it to the client, which would then cause the browser to fail the request.
Update #3:
Submitting a test POST request to the same URL from Chrome's REST Console extension returns the appropriate response headers, as seen in the screencap below.
At this point, I can't determine what's removing the headers between Jersey and my Angular client, but I'm fairly confident that's the culprit.
The problem turned out to be inadequate handling of the OPTIONS request sent in pre-flight prior to the POST request with the proper cross origin headers.
I was able to resolve the issue by downloading and implementing the CORS filter found at this page: http://software.dzhuvinov.com/cors-filter-installation.html.
If you're experiencing a similar problem, follow the instructions and test to see that your OPTIONS request is no longer failing, and is immediately followed by your successful request.
Best way is to add Jersey Response filter which will add the CORS headers for all the methods. You don't have to change your webservices implementation.
I will explain for Jersey 2.x
1) First add a ResponseFilter as shown below
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerResponseFilter;
public class CorsResponseFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext)
throws IOException {
responseContext.getHeaders().add("Access-Control-Allow-Origin","*");
responseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
}
}
2) then in the web.xml , in the jersey servlet declaration add the below
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>YOUR PACKAGE.CorsResponseFilter</param-value>
</init-param>
I had faced similar CORS error while calling my Restful service (implemented in java - Jersey) from angularjs. To fix it I added Access-Control-Allow-Origin: * in response header. I added below :
response.addHeader("Access-Control-Allow-Origin", "*");
For more information you can check - http://enable-cors.org/server.html
CORS error occurs typically when your angularjs code (web project) and webserivce code (server side project) are on different IP and port no.
Your webservice implementation looks correct. So just to check, try running them on localhost on same port (eg. 8080). It should work there if all code is correct.
In order to run them separately try adding Access-Control-Allow-Origin: * in webservice implementation as shown above.
Hope this helps.
Actually, you have other solution that does not need a filter. Adding the Access-Control-Allow-* headers to the GET request, is not enough, you have to create an OPTIONS endpoint to allow browsers do the pre-flight request, i.e.:
#OPTIONS
public Response corsMyResource(#HeaderParam("Access-Control-Request-Headers") String requestH) {
ResponseBuilder rb = Response.ok();
return buildResponse(rb, requestH);
}
see https://kdecherf.com/blog/2011/06/19/java-jersey-a-cors-compliant-rest-api/ for reference.

Access to azure hosted API App denied by CORS policy

We are a team working on azure web services. What we want to achieve is having a JavaScript frontend which can communicate with our Java API App hosted in Azure.
We are using Active Directory for Authentication. And we have configured CORS within the Azure portal.
We have created a Java backend with Swagger Editor as it is described in this article. We have just advanced this example to support our own data model. So also the ApiOriginFilter class is still unchanged:
#javax.annotation.Generated(value = "class io.swagger.codegen.languages.JavaJerseyServerCodegen", date = "2016-11-08T15:40:34.550Z")
public class ApiOriginFilter implements javax.servlet.Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse res = (HttpServletResponse) response;
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
res.addHeader("Access-Control-Allow-Headers", "Content-Type");
chain.doFilter(request, response);
}
public void destroy() {}
public void init(FilterConfig filterConfig) throws ServletException {}
}
Our frontend runs on a local PC. So furthermore, we added our origin "http://localhost:8888" in the CORS in the azure portal.
The frontend JavaScript code looks like this:
var app = angular.module('demo', ['AdalAngular', 'ngRoute'])
.controller('GetDataController', ['$scope', '$http', '$timeout', 'adalAuthenticationService', function($scope, $http, $timeout, adalAuthenticationService) {
$scope.loggedIn = "Logged out";
$scope.responseData = "No Data";
$scope.loading = "";
$scope.loginAdal = function(){
adalAuthenticationService.login();
}
$scope.getData = function(){
$http.defaults.useXDomain = true;
delete $http.defaults.headers.common['X-Requested-With'];
$scope.loading = "loading...";
var erg = $http.get('http://<our-backend>.azurewebsites.net/api/contacts')
.success(function (data, status, headers, config) {
console.log("SUCCESS");
$scope.loading = "Succeeded";
$scope.loggedIn = "LOGGED IN";
$scope.responseData = data;
})
.error(function (data, status, header, config) {
console.log("ERROR");
$scope.loading = "Error";
console.log("data: ", data);
});
}
}]);
app.config(['$locationProvider', 'adalAuthenticationServiceProvider', '$httpProvider', '$routeProvider', function($locationProvider, adalAuthenticationServiceProvider, $httpProvider, $routeProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false,
hashPrefix: '!'
});
var theEndpoints = {
"https://<our-backend>.azurewebsites.net/api/contacts": "f0f91e4a-ad53-4a4a-ac91-431dd152f386",
};
adalAuthenticationServiceProvider.init(
{
anonymousEndpoints: [],
instance: 'https://login.microsoftonline.com/',
tenant: "<our-tenant>.onmicrosoft.com",
clientId: "f6a7ea99-f13b-4673-90b8-ef0c5de9822f",
endpoints: theEndpoints
},
$httpProvider
);
}]);
But calling the backend from the frontend we get the following error after logging in into our tenant:
XMLHttpRequest cannot load https://[our-backend].azurewebsites.net/api/contacts. Redirect from 'https://[our-backend].azurewebsites.net/api/contacts' to
'https://login.windows.net/12141bed-36f0-4fc6-b70c-
43483f616eb7/oauth2/autho…
%2Fapi%2Fcontacts%23&nonce=7658b7c8155b4b278f2f1447d4b77e47_20161115124144'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin'
header is present on the requested resource. Origin 'null' is
therefore not allowed access.
In Chrome's developer console we see four requests to our contacts api. But all have the status code "302 Redirect". The first two entries contain the header "Access-Control-Allow-Origin:http://localhost:8888" but the other two entries do not contain this header.
EDIT: One of the first two entries is an XmlHttpRequest and one of the second entries is the same XmlHttpRequest but with https instead of http.
Based on this, we created a new filter in our backend to set the access-control-allow-origin field:
#Provider
public class CrossOriginFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException {
containerResponseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
containerResponseContext.getHeaders().add("Access-Control-Allow-Headers", "origin, content-type, accept, authorization");
containerResponseContext.getHeaders().add("Access-Control-Allow-Credentials", "true");
containerResponseContext.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
containerResponseContext.getHeaders().add("Access-Control-Max-Age", "1209600");
}
}
and deleted these three fields from ApiOriginFilter:
res.addHeader("Access-Control-Allow-Origin", "*");
res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
res.addHeader("Access-Control-Allow-Headers", "Content-Type");
Now if we run the backend locally, we see all these headers from the 2nd filter in Chrome's developer console.
But as soon as we deploy the backend to azure we loose this headers somehow and again have the same error when accessing the api from the frontend:
XMLHttpRequest cannot load https://[our-backend].azurewebsites.net/api/contacts. Redirect from 'https://[our-backend].azurewebsites.net/api/contacts' to
'https://login.windows.net/12141bed-36f0-4fc6-b70c-
43483f616eb7/oauth2/autho…
%2Fapi%2Fcontacts%23&nonce=7658b7c8155b4b278f2f1447d4b77e47_20161115124144'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin'
header is present on the requested resource. Origin 'null' is
therefore not allowed access.
EDIT: As I wrote there are two XmlHttpRequests made. And the second one is https. So If in the line
var erg = $http.get('http://<our.backend>.azurewebsites.net/api/contacts')
I change http to https we run into the error() callback function. And in the console we have the output:
data: User login is required
But as I wrote before. We are already logged in to our tenant. So what is going wrong?
var erg = $http.get('http://.azurewebsites.net/api/contacts')
Based on the code, you were request the service with HTTP protocol. I am able to reproduce this issue when I request the web API which protected by Azure AD with the HTTP. It seems that the Azure AD will redirect the HTTP to HTTPS.
After I change the service URL with HTTPS, the issue was fixed. Please let me know whether it is helpful.

Angular $http.get always get ERROR consuming local Restful Service

I have an error and I am getting confuse, I have created a simple Java EE 7 project using Jersey.
I am returning this class in my Rest Rervice:
#XmlRootElement
public class LocationDTOx {
private Long id;
private String tittle;
private String description;
private Long parent;
//Getter and setters...
And in my service class i Have:
#Path("/location")
public class LocationService {
#GET
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("/findlocation")
public LocationDTOx findLocation() {
System.out.println("findlocation");
try {
LocationDTOx x = new LocationDTOx();
x.setDescription("Description");
x.setId(0l);
x.setParent(null);
x.setTittle("Tittle ...");
return x;
} catch (Exception ex) {
Logger.getLogger(LocationService.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
}
I am 100% sure that my rest it is working , if I put this in my browser:
http://localhost:8080/BIReportL-war/rest/location/findlocation
I get this Json String:
{"description":"Description","id":0,"tittle":"Tittle ..."}
The deal is in my angular code, the code where I am calling the rest service from angular it is getting executed but it is just giving me the error part:
app.controller('questionsController', function ($scope, $http) {
//var url = "http://localhost:8080/BIReportL-war/rest/location/findlocation";
//var url = "http://www.w3schools.com/angular/customers.php";
var url = "http://127.0.0.1:8080/BIReportL-war/json.json";
$http.get(url)
.success(
function (data, status, headers, config) {
alert("success");
})
.error(function(data, status, headers) {
alert('Repos status ' + status + ' --- headers : ' + headers);
})
.finally(
function() {
});
});
I have with comments another local URL to a dummy json file that I can access it by that browser, and also I get the same result an error, the weird thing is that I tried with this rest public json file:
http://www.w3schools.com/angular/customers.php
And I get the success !! I don't know why, what I am doing or what I have wrong, I mean when I try with my local rest service, I see that it is getting called in the logs, that is a fact, but the angular client is getting into an error.
Thanks in advance for your help !
I am using:
*Glassfish V4
*Angular
Well, was about the CORS Issue I just put my rest as below, so here is the SOLUTION:
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#Path("/findlocation")
public Response findLocation() {
System.out.println("findlocation");
try {
LocationDTOx x = new LocationDTOx();
x.setDescription("Description");
x.setId(0l);
x.setParent(null);
x.setTittle("Tittle ...");
return Response.ok()
.entity(x)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT")
.build();
} catch (Exception ex) {
Logger.getLogger(LocationService.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
If AngularJS is accessing your local REST API, the fact that you're running it in a browser on a different port, it counts as a different origin, per the rules of CORS (separate port means separate origin).
Two pages have the same origin if the protocol, port (if one is
specified), and host are the same for both pages.
For your Access-Control-Allow-Origin response header, either set it to all via *, or specify the alternate ports explicitly. This has to do with the fact that your browser (and AngularJS) are attempting to play by the rules, which you can find on MDN's page on same origin policy.
These "rules" don't apply when you load the resource directly in your browser, as the origin (page your browser is loading from) is the same port, as you're loading just the resource, at that origin (plus port).
[Edit]
The CORS standards included adherence to certain response headers, such as Access-Control-Allow-Origin and Access-Control-Allow-Methods.
References:
MDN's page on access control
HTML5Rocks.com tutorial on CORS
[/Edit]
Your Jersey service is using GET (#GET) while your Angular client is using POST ($http.post(url)).
Change the Angular code to $http.get and you're good to go.
Your example of http://www.w3schools.com/angular/customers.php is working because it responds to both POST and GET, however for your scenario GET is clearly the correct HTTP verb.
Did you try to use relative url? var url = "/BIReportL-war/json.json";
Can you post here the entire error?
I agree with #pankajparkar it might be a CORS problem.
(Sorry for posting this 'answer', I don't have enough points for comments)

Jersey CORS working for GET but not POST

My Jersey CORS request is not functioning for POST, but works for GET requests. The headers are being mapped to Jersey requests as shown in the below screenshot of a GET request to the same resource.
However, doing a POST to the below method makes me end up with XMLHttpRequest cannot load http://production.local/api/workstation. Origin http://workstation.local:81 is not allowed by Access-Control-Allow-Origin.
Here's a screenshot of network activity:
Details on failed POST request:
Here's my resource:
#Path("/workstation")
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public class WorkstationResource {
#InjectParam
WorkstationService workstationService;
#POST
public WorkstationEntity save (WorkstationEntity workstationEntity) {
workstationService.save(workstationEntity);
return workstationEntity;
}
#GET
#Path("/getAllActive")
public Collection<WorkflowEntity> getActive () {
List<WorkflowEntity> workflowEntities = new ArrayList<WorkflowEntity>();
for(Workflow workflow : Production.getWorkflowList()) {
workflowEntities.add(workflow.getEntity());
}
return workflowEntities;
}
}
My CORS filter:
public class ResponseCorsFilter implements ContainerResponseFilter {
#Override
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
Response.ResponseBuilder responseBuilder = Response.fromResponse(response.getResponse());
responseBuilder
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD");
String reqHead = request.getHeaderValue("Access-Control-Request-Headers");
if(null != reqHead && !reqHead.equals(null)){
responseBuilder.header("Access-Control-Allow-Headers", reqHead);
}
response.setResponse(responseBuilder.build());
return response;
}
}
My Jersey configuration in my Main class:
//add jersey servlet support
ServletRegistration jerseyServletRegistration = ctx.addServlet("JerseyServlet", new SpringServlet());
jerseyServletRegistration.setInitParameter("com.sun.jersey.config.property.packages", "com.production.resource");
jerseyServletRegistration.setInitParameter("com.sun.jersey.spi.container.ContainerResponseFilters", "com.production.resource.ResponseCorsFilter");
jerseyServletRegistration.setInitParameter("com.sun.jersey.api.json.POJOMappingFeature", Boolean.TRUE.toString());
jerseyServletRegistration.setInitParameter("com.sun.jersey.config.feature.DisableWADL", Boolean.TRUE.toString());
jerseyServletRegistration.setLoadOnStartup(1);
jerseyServletRegistration.addMapping("/api/*");
While I thought this was a CORS issue, turns out it was a Jersey issue...
org.glassfish.grizzly.servlet.ServletHandler on line 256 handles an exception...
FilterChainInvoker filterChain = getFilterChain(request);
if (filterChain != null) {
filterChain.invokeFilterChain(servletRequest, servletResponse);
} else {
servletInstance.service(servletRequest, servletResponse);
}
} catch (Throwable ex) {
LOGGER.log(Level.SEVERE, "service exception:", ex);
customizeErrorPage(response, "Internal Error", 500);
}
In my log, all I see is service exception: with nothing after it. When I debug this line, I end up seeing the error javax.servlet.ServletException: org.codehaus.jackson.map.JsonMappingException: Conflicting setter definitions for property "workflowProcess": com.production.model.entity.WorkstationEntity#setWorkflowProcess(1 params) vs com.production.model.entity.WorkstationEntity#setWorkflowProcess(1 params) which gives me something I can actually work with.
It's hard to tell and hard to debug since it's the browser that produces that error upon inspecting the response (header).
Even upon very close inspection your code looks fine and sane except that Access-Control-Allow-Headers is or may be set twice in filter(). While RFC 2616 (HTTP 1.1) Section 4.2 does basically permit it given certain conditions are met I wouldn't gamble here. You have no control over how browser X version N handles this.
Instead of setting the same header twice with different values rather append the 2nd set of values to the existing header.

Categories

Resources