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.
Related
I have two microservices. The first one receives a call from the Frontend and then it calls to the second uService to receive some data. The last is returning an error response (Bad Request, this is ok - it is a use-case). However, I am losing the body (message) returned from the second microservice, as the first is throwing a HttpClientErrorException 400 null in the call
This is my code:
ResponseEntity<MyEntity> entityResponse = restTemplate.getForEntity(url, MyEntity.class, id);
I am not able to do entityResponse.getStatusCode() as an exception is thrown.
Handled it in the ControllerAdvice, my exception message is "400 null" even I return a custom message from the service.
So, I would like to get the response message sent in the called uservice to manage it.
Thanks in advance.
The answers here that explain how to catch the exception and access the body are correct. However, you may use a different approach. You can use a 3-d party library that sends Http request and handles the response. One of the well-known products would be Apache commons HTTPClient: HttpClient javadoc, HttpClient Maven artifact. There is by far less known but much simpler HTTPClient (part of an open source MgntUtils library written by me): MgntUtils HttpClient javadoc, MgntUtils maven artifact, MgntUtils Github. Using either of those libraries you can send your REST request and receive response independently from Spring as part of your business logic
What I'm doing in my project is the following.
MicroService_2 calls MicroService_1.
MicroService_1
MicroService_1 returns for example a HTTP 404 exception if the entity isn't found.
#RestController
#RequestMapping(value = "/api/v1/")
public class Service1Controller {
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public #ResponseBody MyEntity getMyEntity(#PathVariable String id) throws NotFoundException {
MyEntity result = ...
if(result == null) {
throw new NotFoundException("MyEntity [id: "+id+"] not found");
}
return result;
}
#ControllerAdvice
public class RestEndpointExceptionHandler extends RestExceptionHandler {
#ExceptionHandler(NotFoundException.class)
public ResponseEntity<String> handleNotFoundException(HttpServletRequest req, NotFoundException ex) throws NotFoundException {
return new ResponseEntity<String>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
}
}
MicroService_2
The MicroService_2 calls MicroService_1 and catches the exception by HTTP code and regenerate the NotFoundException.
#Override
public MyEntity getMyEntity(Principal principal) {
try {
ResponseEntity<MyEntity> entityResponse = restTemplate.getForEntity(url, MyEntity.class, id);
return entityResponse.getBody();
} catch(HttpClientErrorException e) {
HttpStatus status = e.getStatusCode();
if (status == HttpStatus.NOT_FOUND) {
throw new NotFoundException(e.getResponseBodyAsString()); // should be "MyEntity [id: {id}] not found"
} else {
throw new UnexpectedServerException(e.getResponseBodyAsString());
}
}
}
The Spring RestTemplate throws an error in case of 500 or 400 status codes. So if your second service responds with an error an exception will be thrown by the RestTemplate call in your first service.
HttpClientErrorException: in case of HTTP status 4xx
HttpServerErrorException: in case of HTTP status 5xx
UnknownHttpStatusCodeException: in case of an unknown HTTP status
To get the response message you could either catch the exception. E.g:
try {
ResponseEntity<MyEntity> entityResponse = restTemplate.getForEntity(url, MyEntity.class, id);
} catch(HttpStatusCodeException e) {
// e.getResponseBodyAsString();
}
or define a ResponseErrorHandler. The ResponseErrorHandler can be set during the instantiation of the RestTemplate. In the handleError method you will also be able to access the response message.
#Override
public void handleError(ClientHttpResponse httpResponse)
throws IOException {
}
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.
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)
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.
I am using GWT 2.4 to build an application that runs entirely client-side and uses a web service that I control but is hosted on a different server. On this Java Servlet web service, I have implemented doOptions like so:
protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "POST, GET");
}
And client-side in GWT I submit a request the standard way, e.g.
public static void makeHttpGetRequest(String query, RequestCallback callback) {
String url = "http://example.webservice.com/endpoint" + "?q=" + query;
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(url));
try {
builder.sendRequest(query, callback);
} catch (RequestException e) {
Window.alert("Server encountered an error: \n" + e.getMessage());
e.printStackTrace();
}
}
And then my callback implements onResponseReceived like this:
#Override
public void onResponseReceived(Request request, Response response) {
if (response.getStatusCode() == 200) {
System.out.println("HTTP request successful, received "
+ response.getText());
processResponse(response.getText());
} else {
System.out.println("HTTP error code " +
response.getStatusCode() + ":" +
response.getStatusText());
}
}
Whenever I run the application in late versions of Chrome or Firefox and send a request, onResponseReceived is called but the response code is 0 and there is no error message. Research indicates that most other instances of this problem arise from SOP restrictions. However, when looking at the HTTP traffic in Fiddler I see that when this is executed, the browser is indeed sending the expected HTTP request, and the web service is indeed returning the expected response, with a 200 response code. Somehow, the browser just isn't handling it properly.
Update: when I look at the traffic in Fiddler, it indicates that the request is sent and a response is received, but when I look at the same request in Chrome's developer console it shows that the request is 'canceled'. If the request is actually happening, what does that mean in this context?
Has anyone run across this problem? Any suggestions on what may be going on?
Error code 0 means that the CORS has been aborted, check that your servlet implementation is all right, I think you have to send Allow instead of Access-Control-Allow-Methods, and also you have to add the Access-Control-Allow-Headers since GWT adds extra headers to ajax requests.
Try this implementation from the gwt-query example which works fine:
private static final String ALLOWED_DOMAINS_REGEXP = ".*";
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
String origin = req.getHeader("Origin");
if (origin != null && origin.matches(ALLOWED_DOMAINS_REGEXP)) {
resp.addHeader("Access-Control-Allow-Origin", origin);
resp.setHeader("Allow", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS");
if (origin != null) {
String headers = req.getHeader("Access-Control-Request-Headers");
String method = req.getHeader("Access-Control-Request-Method");
resp.addHeader("Access-Control-Allow-Methods", method);
resp.addHeader("Access-Control-Allow-Headers", headers);
resp.setContentType("text/plain");
}
}
I would rather a filter instead a servlet, like in the link above is explained, though.