POST request with multipart data in spring mvc - java

I am using ng-file-upload in Angular on client side to send a file(image,text etc) to Spring Boot Application.
I have Client side running in Xampp with url "localhost" while have spring instance running separately with url "localhost:8080".Cors on both sides are enabled and other all requests are successfully entertained.
Client Side Code:
Upload.upload({
url: 'http://localhost:8080/file/upload',
method:'POST',
data: {
uploadedPicture: file,
uploadedFrom: 'recipe'
},
}).then(function(response) {
$timeout(function() {
$scope.result = response.data;
});
}, function(response) {
if (response.status > 0) $scope.errorMsg = response.status + ': ' + response.data;
}, function(evt) {
$scope.progress = parseInt(100.0 * evt.loaded / evt.total);
});
Server Side Code:
#CrossOrigin
#RequestMapping(method = RequestMethod.POST, value = "/file/upload")
public String handleFileUpload(#RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) {
if (!file.isEmpty()) {
try {
Files.copy(file.getInputStream(), Paths.get(ROOT, file.getOriginalFilename()));
redirectAttributes.addFlashAttribute("message",
"You successfully uploaded " + file.getOriginalFilename() + "!");
} catch (IOException|RuntimeException e) {
redirectAttributes.addFlashAttribute("message", "Failued to upload " + file.getOriginalFilename() + " => " + e.getMessage());
}
} else {
redirectAttributes.addFlashAttribute("message", "Failed to upload " + file.getOriginalFilename() + " because it was empty");
}
return "redirect:/";
}
I have tried the cors by sending get request from same code to the same resource with get method which is working.but when i send post request with a multipart form data (image or any other file) it rejects OPTIONS request.
OPTIONS http://localhost:8080/file/upload
XMLHttpRequest cannot load http://localhost:8080/file/upload. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access. The response had HTTP status code 403.
I have Tested This resource by postman also and it uploaded file without error.
EDIT: I have tried by changing the http to https and it is giving the error as OPTIONS https://localhost:8080/file/upload net::ERR_TIMED_OUT_ problem is same as it cannot find the required resource
Any thoughts over this issue??

Looking at your error message I see:
No 'Access-Control-Allow-Origin' header is present
Are you sure the proper headers are being added?
We used a Filter to ensure all requests had these Headers added correctly:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST,GET, OPTIONS, DELETE
Access-Control-Max-Age: 3600
Access-Control-Allow-Headers: x-requested-with
Here is the Filter class we used:
SimpleCORSFilter.java
#Component
public class SimpleCORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}

Just change #CrossOrigin annotation to:
#CrossOrigin(origins = "*", methods = {RequestMethod.POST, RequestMethod.OPTIONS}, allowedHeaders = {"Content-Type", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers"}, exposedHeaders = {"Access-Control-Allow-Origin", "Access-Control-Allow-Credentials"})

try this extension in chrome , it may help you with the problem
https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=fr

First check your security settings, since you obviously get 403 as Status Code. Maybe your redirect at the end causing problems, try without it.
Here is a code sample, I was using a while ago to add CORS-headers:
#RequestMapping(value="/GetSomething", method = RequestMethod.GET, produces = "application/json;charset=UTF-8")
public ResponseEntity<String> getSomething() throws IOException {
HttpHeaders responseHeaders = new HttpHeaders();
//need for cross-domain requests
responseHeaders.add("Access-Control-Allow-Origin", "*");
//this one is needed, if your browser should send cookies
responseHeaders.add("Access-Control-Allow-Credentials", "true");
...
responseHeaders.setContentLength(resp.getBytes("UTF-8").length);
return new ResponseEntity<String>(resp, responseHeaders, HttpStatus.OK);
}
EDIT: removed session-parameter
EDIT2: can you check, if the code in your POST-request is actually being executed? Make some logs in the function. If your code is not executed, then you clearly have security setup issue and your request doesn't go through security layer. CORS is client-based functionality, it can only block data AFTER the browser get it from server!

I had faced this problem before in my current project, after a lot RND and some experiments, i have found that the problem was with the content type, whenever there is a image upload will take a place to upload content type is matter a much here.
I haven't test this, but let me know after try this by replace in your code near...
var fd = new FormData();
fd.append('uploadedPicture', file);
fd.append('uploadedFrom', 'recipe');
Upload.upload({
url: 'http://localhost:8080/file/upload',
method: 'POST',
data: fd,
transformRequest: angular.identity,
headers: {'Content-Type': undefined},
}).then(function (response) {
$timeout(function () {
$scope.result = response.data;
});
}, function (response) {
if (response.status > 0)
$scope.errorMsg = response.status + ': ' + response.data;
}, function (evt) {
$scope.progress = parseInt(100.0 * evt.loaded / evt.total);
});
Let me know please after try this.

It makes no sense to return a redirect from an Ajax call. Firstly determine if the issue is with the form post or with the subsequent action. To do so change your Controller as below:
#CrossOrigin
#RequestMapping(method = RequestMethod.POST, value = "/file/upload")
#ResponseBody
public String handleFileUpload(#RequestParam("file") MultipartFile file) {
String status = null;
if (!file.isEmpty()) {
try {
Files.copy(file.getInputStream(), Paths.get(ROOT, file.getOriginalFilename()));
status = "okay";
} catch (IOException|RuntimeException e) {
status = "error";
}
} else {
status = "error";
}
return "status"; // a literal string
}
I would also note that the params sent from the front-end do not match what the backend expects. Where in the front-end do you specify a parameter named 'file' which is what the controller is going to map to the specified RequestParam?
The library in question has an end to end example using Spring MVC here:
https://github.com/danialfarid/ng-file-upload/wiki/spring-mvc-example
Note how the parameter names match on both sides.

Add the content type see this answer it may help Request not found ajax spring mvc and origins = "/**"

Related

CORS enabled on Java Servlet yet receiving CORS error from frontend

I am writing a web application where the client posts (JSON) form data to the and the server should also respond with a JSON. The server-side is written using java servlets, running on Tomcat and the client is written in Angular 7. Unfortunately, I am facing a CORS error even after enabling cors via the HTTP headers. Is there anything I am missing?
This is the error I get on the client side:
Access to XMLHttpRequest at 'http://localhost:8080/mysocial/signIn' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I have read the following posts and tried each of the solutions but the problem still persists:
CORS enabled but still getting CORS error
How to fix CORS issue http request in Angular 5
As I have said I have enabled the CORS headers. The code snippets show my server side and client side code:
// From my data service (client-side angular 7)
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class DataService {
private baseUrl: string = "http://localhost:8080/mysocial";
private http: HttpClient;
constructor(http: HttpClient) {
this.http = http;
}
public authenticateLogin(username: string, password: string) //: boolean
{
let url: string = `${this.baseUrl}/signIn`;
let header = new HttpHeaders({'Accept': 'application/json' ,'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
let httpOptions = { headers: header };
let body = {username: username, password: password};
return this.http.post(url, body, httpOptions).subscribe(
(response) => console.log(response),
(err) => console.log(err)
);
//return true;
}
}
Server-side code:
// server-side java servlets code
private void configResponse(HttpServletResponse response)
{
response.setContentType("application/json");
response.addHeader("Access-Control-Allow-Origin", "http://localhost:4200");
response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD");
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
Model model = (Model) getServletContext().getAttribute("model");
String username = request.getParameter("username");
String password = request.getParameter("password");
configResponse(response);
PrintWriter out = response.getWriter();
if (model.validateLoginDetails(username, password))
{
String firstName = model.getUserInfo("firstName", "username", username);
int id = Integer.parseInt(model.getUserInfo("id", "username", username));
HttpSession session = request.getSession();
session.setMaxInactiveInterval(60);
session.setAttribute("username", username);
session.setAttribute("firstname", firstName);
session.setAttribute("id", id);
JsonObject value = createJsonResponse(username, password, true);
out.println(value);
}
else
{
JsonObject value = createJsonResponse(username, password, false);
out.println(value);
}
}
I expect the server to send a JSON back to the client but I'm getting a CORS error from the client.
Just for completeness and for anyone who may come across this problem, I was able to solve this problem using the tomcat filters provided here: http://tomcat.apache.org/tomcat-7.0-doc/config/filter.html#CORS_Filter (shown by sideshowbarker (https://stackoverflow.com/users/441757/sideshowbarker))
There had to change some server configurations first to match the filter. I'd suggest customizing the filter to your needs.

Http failure response for localhost api request: 0 Unknown Error - Angular

I'm trying to create a communication to my Java Jetty Backend from my Angular application. When I try to execute my request I receive the following error:
My code on client side: (Angular 7.2.1). I'm also using a HttpInterceptor for authentication that should work. I'm also running the code in development mode with ng serve.
#Injectable({
providedIn: 'root'
})
export class NgHydrantService {
constructor(private http: HttpClient) {
}
public register(entity: IEntityDescription): Observable<StandardResponsePacket> {
let packet = new RegisterEntityRequestPacket(entity);
return this.http.post(this._apiUrl, packet.toJson())
.pipe(
map(value => {
console.log('register result:', value); //<-- never executed
return <StandardResponsePacket>HydrantPackage.fromJson(value)
})
);
}
}
//The interceptor
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// add authorization header with basic auth credentials if available
if (this.user != null) {
const clonedRequest = request.clone({
headers: request.headers.set('Authorization', `Basic ${this.user.getAuth()}`)
.set('Accept','application/json')
});
//This debug line works and looks good!
console.log('NgHydrantAuthInterceptor#intercept', clonedRequest);
return next.handle(clonedRequest);
}
return next.handle(request);
}
My Code on server side: (Jetty-9.4.14.v20181114) that runs on localhost.
public final class PacketHandler extends AbstractHandler
{
#Override
public void handle( String target,
Request baseRequest,
HttpServletRequest request,
HttpServletResponse response ) throws IOException
{
try
{
// Declare response encoding and types
response.setContentType( "application/json; charset=utf-8" );
// Enable CORS
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD");
response.addHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Origin, X-Requested-With, Content-Type, Accept");
response.addHeader("Access-Control-Max-Age", "1728000");
//... more stuff
}
finally
{
// Inform jetty that this request was handled
baseRequest.setHandled( true );
}
}
}
Things I checked:
During research some people reference problems with CORS (that's why I added the header entries in the server side code)
The same request in Postman works without any problems
There are no logs on the server side
My question is about a possible solution to get responses from my server during development.
Can you please follow the steps in below link
https://www.html5rocks.com/en/tutorials/cors/
For quick solution add below plugin in your chrome
https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi?hl=en
i was able to solve a likely problem by setting my web server configuration to allow the cors policy. In my case, i use Nginx web server follow the configuration in this link https://enable-cors.org/server_nginx.html

How to redirect/forward angular page from spring boot?

I am developing a application with angular 6 as front end and spring boot as back end. In this while implementing user authentication module I want to redirect to student and staff home after login accordingly.
But, I am not able to redirect the page from spring boot. Using Redirect to an external URL from controller action in Spring MVC this solution I am getting the CORS error :
"Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response."
Or, if there is another way to do this task?
AuthenticationController.java
package sgsits.cse.dis.user.controller;
#CrossOrigin(origins = "*") // enables cross origin request
#RestController
#RequestMapping(value = "/dis")
#Api(value = "Authentication Resource")
public class AuthenticationController {
#Autowired
StudentRepository studRepo;
#Autowired
StaffRepository staffRepo;
#Autowired
EmailController email;
String pattern = "MM-dd-yyyy";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
#ApiOperation(value = "login", response = Object.class, httpMethod = "POST", produces = "application/json")
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(#RequestBody Authentication auth, HttpServletResponse httpServletResponse) {
Optional<StaffProfile> staff = staffRepo.findByEmail(auth.getUsername());
if (staff.isPresent()) {
String md5_pass = MD5.getHash(auth.getPassword());
if (staff.get().getPassword().equals(md5_pass)) {
// set session
// update last login
return "forward:/localhost:4200/staff";
} else
return "You have entered incorrect password";
} else {
Optional<StudentProfile> student = studRepo.findByEnrollmentId(auth.getUsername());
if (student.isPresent()) {
String md5_pass = MD5.getHash(auth.getPassword());
if (student.get().getPassword().equals(md5_pass)) {
// set session
// update last login
httpServletResponse.setHeader("Location", "http://localhost:4200/reset-password");
httpServletResponse.setStatus(302);
return "redirect:localhost:4200/student";
} else
return "You have entered incorrect password";
} else {
return "You are not registered with the system. Please signup first";
}
}
}
}
Do not add #CrossOrigin(origins = "*") annotation to controller.
Assume your api runs on 8080 and your angular code on 4200. If true;
create a file called proxy.conf.json
{
"/api/": {
"target": "http://localhost:8080/",
"secure": false,
"changeOrigin": true
}
Start angular app using this command
ng serve --proxy-config proxy.conf.json
With this configuration when you call localhost:4200/api you it will call 8080 and it won't have any CORS error
Why don't you return a proper API Response and code and depending on your response and Code you can redirect on the front end.
It makes your API Completely RESTFUL. I hope this helps.
I observed that when you redirect from Spring Boot to an Angular page the error "request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response" means that, Angular node.js server does not detect field content-type in the header Access-Control-Allow-Headers in your Angular app configuration. The point here is that roles of backend server and and client app are a bit the other way around in this redirection.
To solve this I would add content-type field into the response header Access-Control-Allow-Headers in the following way:
1. create file proxy.config.js just below the package.json file in your Angular project with this code:
module.exports = {
"/": {
"secure": false,
"bypass": (req, res, proxyOptions) => {
res.setHeader('Access-Control-Allow-Headers', "Content-Type");
}
}
};
and modify angular.json file by adding line:
"proxyConfig": "proxy.config.js"
to this location:
projects >> client >> architect >> serve >> options
This solution worked in my case. Note that the capitalization of first letter of the field name matters.

Supply response from Spring to Angularjs

I am trying to get the response from the spring controller to Angularjs get request
Here is the java code
#RequestMapping(method = RequestMethod.GET, value = "/getEmployee")
public ResponseEntity<List<EmployeeModel>> getEmployee() {
System.out.println("get List");
List<EmployeeModel> em=employeeService.getEmployee();
return new ResponseEntity<List<EmployeeModel>>(em, HttpStatus.OK);
i have the list of EmployeeModel in em variable
but somehow i am not able to get it in the data of angularjs response(success)
Here is the angularjs code
$scope.listEmployee = function() {
$http({
method : 'GET',
url : '/Employee/getEmployee'
}).success(function(data, status, headers, config) {
console.log("data.token " + data);
}).error(function(data, status, headers, config) {
console.log("data.token " + data.token);
});
};
browser Status Code:406 Not Acceptable
Please help
Add following lines to your pom.xml
dependency groupId org.codehaus.jackson jackson-mapper-asl 1.7.1
Try adding following all HTTP headers to your request in following manner
HttpHeaders headers= new HttpHeaders(); List medias = new ArrayList(); medias.add(MediaType.ALL); headers.setAccept(medias);
And add headers as a second argument before sending response
. It will ensure data format is acceptable to any kind of accept header .

ajax call to jax-rs with jquery issue

I'm trying to call a Webservice that consumes a json object with post method .I did it then It wont work again don't know what is the problem.
here is my method
#POST
#Path("/post")
#Consumes("application/json")
#Produces("application/json")
public Response testClient(Client c) throws IOException {
System.out.println(c.getAdresseCl());
ResponseBuilder builder = Response.ok(c.getAdresseCl());
builder.header("Access-Control-Allow-Origin", "*");
builder.header("Access-Control-Max-Age", "3600");
builder.header("Access-Control-Allow-Methods", "*");
builder.header(
"Access-Control-Allow-Headers",
"X-Requested-With,Host,User-Agent,Accept,Accept-Language,Accept-Encoding,Accept-Charset,Keep-Alive,Connection,Referer,Origin");
return builder.build();
}
to call this I used this
$.ajax({
type: 'POST',
url: "http://localhost:9080/FournisseurWeb/jaxrs/clients/post",
data: '{"adresseCl":"tunis"}',
dataType:'json',
contentType: "application/json; charset=utf-8",
success: function (msg) {
alert(msg);
},
error: function (xhr, ajaxOptions, thrownError) {
alert('error');
}
});
well I remark that when I set the contentType to application/json the method changes to OPTIONS .
and when I don't use the content type I got "415 Unsupported Media Type " I dont know how to fix this. I passed too much time without results :(thank you for helping me
When attempting to make cross-domain AJAX requests in certain browsers, it is a common to see the HTTP Method change to OPTIONS in lieu of a more meaningful error message.
I noticed in your URL that you're including the protocol, domain, and port, which supports the theory that you're actually trying to make an AJAX request to a different domain/port combination than the originating context.
To clarify, even if your request is originating from localhost and targeting localhost, the ports (9080) and protocols (http) must also match.
Thus, if the page you loaded is "http://localhost:8080" and you're trying to make an AJAX request to "http://localhost:9080", the request will fail, may throw same-domain security errors, 415 Unsupported Media Type, and/or change the HTTP Method to OPTIONS.
One way to make sure you avoid this mistake is to only use full or relative paths when making AJAX requests, such as:
url: "/FournisseurWeb/jaxrs/clients/post",
This forces you to always make requests to the same domain.
Cross-domain Requests
If you do indeed require the ability to make cross-domain requests, this is possible, but only through two methods.
First, you can use a proxy, where you make an HTTP request to your domain and then forward the request onto another server. Servers need not be concerned with same-domain policies when sending and receiving data from one another.
Second, you can use JSONP, also known as script tag remoting, which involves exploiting the <script> element's ability to send requests across different domains.
// added callback= query parameter to convert this to JSONP
$.ajax({
type: 'POST',
url: "http://localhost:9080/FournisseurWeb/jaxrs/clients/post?callback=",
data: '{"adresseCl":"tunis"}',
dataType:'json',
contentType: "application/json; charset=utf-8",
success: function (msg) {
alert(msg);
},
error: function (xhr, ajaxOptions, thrownError) {
alert('error');
}
});
NOTE: When using JSONP, your server must respond with the JSON wrapped up in a function call identified by the callback parameter. See the jQuery documentation for more in-depth details .
Other than that, you must make AJAX requests to the same domain the page was loaded from.
this is the method that consumes a text xml fomat and map it to an object to persist it next
#POST
#Path("/inscription")
#Produces(MediaType.TEXT_HTML)
public Response testClient(String s) {
ResponseBuilder builder = null;
try {
final String xmlString = s;
final StringReader xmlReader = new StringReader(xmlString);
final StreamSource xmlSource = new StreamSource(xmlReader);
final JAXBContext jaxbContext = JAXBContext
.newInstance(Client.class);
final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
final Client client = (Client) unmarshaller.unmarshal(xmlSource,
Client.class).getValue();
System.out.println("nomCl : " + client.getNomCl());
System.out.println("prenomCl : " + client.getPrenomCl());
System.out.println("emailCl : " + client.getEmailCl());
System.out.println("numTel : " + client.getNumTel());
System.out.println("long_ : " + client.getLong_());
System.out.println("lat : " + client.getLat());
System.out.println("LoginCl : " + client.getLoginCl());
System.out.println("PasswordCl : " + client.getPasswordCl());
System.out.println("adresseCl : " + client.getAdresseCl());
EntityManagerFactory factory;
factory = Persistence.createEntityManagerFactory("FournisseurWeb");
EntityManager em = factory.createEntityManager();
em.getTransaction().begin();
em.persist(client);
em.getTransaction().commit();
em.close();
factory.close();
builder = Response.ok("true");
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
builder = Response.ok("false");
builder.header("Access-Control-Allow-Origin", "*");
builder.header("Access-Control-Max-Age", "3600");
builder.header("Access-Control-Allow-Methods", "POST");
builder.header(
"Access-Control-Allow-Headers",
"X-Requested-With,Host,User-Agent,Accept,Accept-Language,Accept-Encoding,Accept-Charset,Keep-Alive,Connection,Referer,Origin");
return builder.build();
}
builder.header("Access-Control-Allow-Origin", "*");
builder.header("Access-Control-Max-Age", "3600");
builder.header("Access-Control-Allow-Methods", "POST");
builder.header(
"Access-Control-Allow-Headers",
"X-Requested-With,Host,User-Agent,Accept,Accept-Language,Accept-Encoding,Accept-Charset,Keep-Alive,Connection,Referer,Origin");
return builder.build();
}
I use to call this method using ajax with this sample :
var x="<client><nomCl>Taarit</nomCl><prenomCl>Aymen</prenomCl><emailCl>aymen.taarit#gmail.com</emailCl><numTel>222</numTel><long_>1.66</long_></client>";
$.ajax({
url: 'http://localhost:9080/FournisseurWeb/jaxrs/clients/cl',
type: 'post',
scriptCharset: "utf-8" ,
dataType:"xml",
data: x,
success: function(data, status) {
console.log(data);
}
});
this is a jax-rs call with ajax POST using cross domain so hope that it helps :)
NOTE: The cross-domain call without JSONP is legal here because the server is returning the following header, which enables cross-domain AJAX!
builder.header("Access-Control-Allow-Origin", "*");
See Mozilla Developer Center page on Access-Control-Allow-Origin for more details.

Categories