Spring Boot — Enable CORS in Restful Web Services | Code Factory

Code Factory
5 min readApr 17, 2020

--

Reference Link : Link

Donate : Link

CORS Stands for Cross-Origin Resource Sharing, As a security measure browsers will block AJAX request to the resource residing on a different origin.

CORS is a W3 Specification, which is implemented by most of the browsers and lets us request for the resource on the different domain in a safer way. (Only when the other domain sends back the response with some special Access-control headers).

In order to demonstrate how CORS works, we will be developing 2 web applications (Spring Boot RESTful Web Services and Spring Boot RESTful Web Services Client) both runs on localhost but on different ports (8080, 7070).

We will be Enable CORS in Spring Boot Restful Web Services using @CrossOrigin annotation.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.codeFactory</groupId>
<artifactId>SpringBootRestCORS</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringBootRestCORS</name>
<description>Spring Boot CORS Example</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

SpringBootRestCorsApplication.java

package com.codeFactory;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author code.factory
*
*/
@SpringBootApplication
public class SpringBootRestCorsApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootRestCorsApplication.class, args);
}
}

Employee.java

package com.codeFactory.model;/**
* @author code.factory
*
*/
public class Employee {
private int id;
private String name;
private int age;
public Employee() {}public Employee(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Employee [id : " + id + ", name : " + name + ", age : " + age + "]";
}
}

Spring @CrossOrigin annotation

Spring 4.2 has introduced @CrossOrigin annotation to handle CORS, this annotation can be used in both class level and method level of the Restful Web Services. @CrossOrigin annotation has the below attributes in it.

  1. origins — This attribute sets value for Access-Control-Allow-Origin in both the pre-fligh and actual response, by default all origins are allowed.
  2. allowedHeaders — This attribute controls the value of the pre-flight response’s Access-Control-Allow-Headers header
  3. exposedHeaders — This attribute sets the value for Access-Control-Expose-Headers.
  4. maxAge — This attribute sets value for Access-Control-Max-Age response header, the default value is 1800 seconds.
  5. methods — The Methods specified here override the methods specified in @RequestMapping.If this is not defined, methods defined by @RequestMapping annotation are used.

EmployeeController.java

package com.codeFactory.controller;import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.codeFactory.model.Employee;/**
* @author code.factory
*
*/
@RestController
@CrossOrigin(origins = "http://localhost:7070", maxAge = 2000,
allowedHeaders = "header1, header2", exposedHeaders = "header1", allowCredentials = "false")
public class EmployeeController {
@DeleteMapping(value = "/employee/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
@CrossOrigin(origins = "http://localhost:9090", exposedHeaders = "deleteHeader")
public List deleteEmployee(@PathVariable Integer id) {
Employee employee1 = new Employee(1, "Emp1", 10);
Employee employee2 = new Employee(2, "Emp2", 20);
Employee employee3 = new Employee(3, "Emp3", 30);

List<Employee> employeeList = new CopyOnWriteArrayList<Employee>();
employeeList.add(employee1);
employeeList.add(employee2);
employeeList.add(employee3);

for(Employee e : employeeList) {
if(e.getId() == id) {
employeeList.remove(id - 1);
}
}

return employeeList;
}
}

We have used the @CrossOrigin annotation in both class and method level, So the deleteEmployee() method will have combined effect of both class and the method level @CrossOrigin annotation. It will allow origin “http://localhost:7070” and “http://localhost:9090” and exposeHeader will be “header1” and “deleteHeader”

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.8.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.codeFactory</groupId>
<artifactId>SpringBootRestCORSClient</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>SpringBootRestCORSClient</name>
<description>Spring Boot CORS Example</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

application.properties

server.port=7070

SpringBootRestCorsClientApplication.java

package com.codeFactory;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author code.factory
*
*/
@SpringBootApplication
public class SpringBootRestCorsClientApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootRestCorsClientApplication.class, args);
}
}

index.html

<!DOCTYPE html>
<html>
<head>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$("button").click(function() {
$.ajax({
url : "http://localhost:8080/employee/" + $("#empId").val(),
method : "delete",
success : function(result) {
console.log(result);
$("#div1").html(result);
}
});
});
});
</script>
</head>
<body>
<div id="div1">
</div>
<input type="text" id="empId"><button>Button</button></body>
</html>

We will be running two Tomcat server instances one on 8080 port (SpringBootRestCORS) and other on 7070 port (SpringBootRestCORSClient).

Hit http://localhost:7070/index.html

pre-flight request

actual request

--

--