No 'Access-Control-Allow-Origin' header present in request - java

I have read a lot of topic about this, and it still doesn't work, i'm loosing my mind.
I have an Angular6 App, with a Spring Api and i keep having this error when i call it :
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
And yet i feel i did everything :
Here is my call to the api in Angular App:
getGamesFromServer() {
const httpOptions = {
headers: new HttpHeaders({
'Access-Control-Allow-Origin':'*'
})
};
this.httpClient
.get<any[]>('http://localhost:8080/api/rest/v1/game/progress', httpOptions)
.subscribe(
(response) => {
console.log(response);
this.games = response;
console.log(this.games);
this.emitGameSubject();
},
(error) => {
console.log('Erreur ! : ' + error);
}
);
}
Here is the java method called :
#RequestMapping(method = GET, value = "/progress")
#ResponseBody
public Response findAllAndProgress() {
return Response.status(Response.Status.OK)
.entity(gameService.findAllAndProgress())
.header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
.build();
}
I have also started chrome with --disable-web-security option activated, and i also downloaded a chrome extension to allow CORS request but it was no use

I'm assuming it's because the Angular app is running in dev mode and is being served from a different port than the Spring webapp. You can either solve this with a proxy.conf.json file that you specify to the app startup (ng serve --proxy-config proxy.conf.json) or as a quick and dirty (but less production ready) solution you can add #CrossOrigin(origins = "*") to your Spring controllers.
The reason that the following code doesn't work:
#RequestMapping(method = GET, value = "/progress")
#ResponseBody
public Response findAllAndProgress() {
return Response.status(Response.Status.OK)
.entity(gameService.findAllAndProgress())
.header(ACCESS_CONTROL_ALLOW_ORIGIN, "*")
.build();
}
is because that method never actually gets executed to add the header. Cross-origin requests initiate a preflight request (HTTP OPTION) before issuing the actual request (HTTP GET in your case). It is that preflight request that is failing. This is why adding the annotation to the controller will address the issue.

Create proxy.conf.json file in root directory with next content:
{
"/api/*": {
"target": "http://localhost:8080",
"secure": false
}
}
And in package.json file you must change start script from ng serve to ng serve --proxy-config proxy.conf.json
More details about proxy-config: Link

On java add following this line on your api
#CrossOrigin(origins = "http://localhost:4200")
You can also proxy your request from Angular side. Angular provide you inbuilt server that can proxy request. Following following steps:
Add proxy.config.json file on root directory of your project.
Add following code in proxy.config.json file
{
"/api/": {
"target": {
"host": "localhost",
"protocol": "http:",
"port": 8080
},
"secure": false,
"changeOrigin": true,
"logLevel": "debug"
}
}
In package.json find start under scripts and replace with following:
ng serve --proxy-config proxy.config.json
Edit your angular code with following code:
this.httpClient
.get('/api/rest/v1/game/progress', httpOptions)
.subscribe(
(response) => {
console.log(response);
this.games = response;
console.log(this.games);
this.emitGameSubject();
},
(error) => {
console.log('Erreur ! : ' + error);
}
);

Related

Error 500 when use axios call service on Linux enviroment but working on local on Windows

I use react for frontend and Java for Backend.
When i call service on local. It'work but error 500 on test enviroment(linux)
React (Frontend) :
const getDatas = async () => {
const config = {
method: 'get',
url: process.env.REACT_APP_API_URL + 'get-all-to-acc-transaction',
withCredentials: true,
params: {
type: '01',
objectType: null,
},
}
const result = await axios(config);
if (result.data.code == '00') {
//todo somethings
}
}
Java (Backend)
#GetMapping("/get-all-acc-transaction-combobox")
public ResponseEntity<Object> getAllAccTransactionCombobox(#RequestParam String type) {
return txnManualService.getAllAccTransactionCombobox(type);
}
Url API local:
http://localhost:2998/project-test/get-all-acc-transaction-combobox?type=1
Url API test environment:
http://10.23.8.187:2998/project-test/get-all-acc-transaction-combobox?type=1
When change url test enviroment to:
http://10.23.8.187:2998/project-test/get-all-acc-transaction-combobox?type='1'. It work.
So where did I go wrong? I think the backend is still receiving the parameter type is string and the axios passing is numeric so the error. Thanks everyone :(((

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.

Unable to upload file from Angular client to Spring Java server: Says 400 error

When I am uploading a file from Postman rest client to the server(spring application deployed on a remote machine), I am able to upload the file without any issue.
But when I try to write a rest client in angular.js, and send over the request, I get 400 Bad Request Error. I know it's because of some syntax issue between what is send from client and what server is expecting.
Server side code:
#CrossOrigin(origins = "*")
#RequestMapping(value="/upload", method=RequestMethod.POST, consumes = {"multipart/form-data"})
public #ResponseBody String handleFileUpload(#RequestParam("files") MultipartFile file){
.
.
.
.
}
Client side code:
$scope.uploadFiles = function () {
alert("inside");
var request = {
method: 'POST',
url: 'http://IP ADDRESS and PORT NUMBER/upload',
data: formdata,
headers: {
'Content-Type': undefined
}
};
$http(request)
.success(function (response) {
alert("success: "+response);
})
.error(function (err) {alert("error: "+err);
});
}
I have uploaded the code here for file upload using Spring and AngularJS:
https://gist.github.com/abdulrafique/9219f7164fdf5dc6dfa8da110be6a04e

why '/test' goes to 'localhost:8080/test' instead of 'localhost:8080/rootcontext/test'

I have created a dynamic web project in eclipse using maven 3 .i used from angularjs in client side and spring and spring security as backend technology.
when i run project it correctly redirects to to the root context and login page,
but when i want to run this javascript :
angular.module('common')
.controller('BaseFormCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.login = function (username, password) {
$http({
method: 'POST',
url: '/authenticate',
data: postData,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"X-Login-Ajax-call": 'true'
}
})
.then(function(response) {
if (response.data == 'ok') {
window.alert("login success");
}
else {
window.alert("login faild");
}
});
}
}])
it return this error:
POST http://localhost:8080/authenticate 404 (Not Found)
but i expect that it call this: http://localhost:8080/avl-web/authenticate
which avl-web is my root context
Putting a '/' at the start of the URL will go to the host, regardless of what your root context is.
'/avi-web/authenticate'
Including the root context will allow you to use absolute Urls like that.

Enable CORS Post Request from AngularJS to Jersey

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.

Categories

Resources