Introduction to CORS
When discussing AJAX cross-domain requests, many developers first think of JSONP. JSONP has been widely used for years, but it has significant limitations. It works by injecting a <script> tag into the page to execute remote JavaScript, which can lead to XSS vulnerabilities if the source is compromised. Additionally, JSONP is not based on XMLHttpRequest, limiting error handling options, and it only supports GET requests, making it unsuitable for RESTful APIs.
This is where CORS (Cross-Origin Resource Sharing) comes in. CORS defines a modern approach for browsers and servers to securely share content across domains, serving as a successor to JSONP. It allows fine-grained control over cross-domain access, specifying allowed origins, HTTP methods, request headers, and content types. CORS enables XMLHttpRequest to work across domains, allowing developers to write AJAX code as usual.
All modern browsers support CORS, making it a reliable choice, with JSONP reservde as a fallback for legacy browser compatibility.
How CORS Works
Browsers supporting CORS initiate a preflight check with an OPTIONS request when attempting cross-domain XMLHttpRequest. This request includes headers such as:
Access-Control-Request-Headers: accept, content-type
Access-Control-Request-Method: POST
The server responds with headers like:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-Requested-With, Content-Type, Accept
Access-Control-Max-Age: 1728000
The browser evaluates the server's response to determine if the request is permitted, checking the origin against Access-Control-Allow-Origin, the HTTP method against Access-Control-Allow-Methods, and request headers against Access-Control-Allow-Headers. If all conditions are met, the request proceeds, and the preflight check is skipped for the duration specified in Access-Control-Max-Age (in seconds, e.g., 20 days).
Note that Access-Control-Allow-Headers cannot use wildcards. To allow all headers, you can echo back the Access-Control-Request-Headers from the browser.
For simple requests (GET, HEAD, POST with MIME types like application/x-www-form-urlencoded, multipart/form-data, or text/plain, and no custom headers), browsers only check the Origin header against Access-Control-Allow-Origin. However, RESTful APIs often use application/json, requiring the preflight check method.
CORS also supports sending cookies in cross-domain requests by setting the withCredentials property on the XMLHttpRequest object:
const request = new XMLHttpRequest();
request.withCredentials = true;
In this case, Access-Control-Allow-Origin must specify a concrete origin (e.g., http://example.com) rather than a wildcard (*).
Configuring CORS in Spring MVC
CORS is a browser technology specification that allows web services to interact across domains, bypassing the same-origin policy. It supports various HTTP methods beyond GET and integrates with XMLHttpRequest for better error handling compared to JSONP.
In practice, JavaScript and cookies are restricted from accessing content under different domains. CORS addresses this cross-domain communication challenge, offering a modern solution that simplifies frontend development.
Implemantation Methods
There are three primary ways to implement CORS:
- Tomcat Configuration: Involves adding external JAR files and modifying
web.xml. This method is not recommended due to its complexity and reliance on third-party libraries. - Interceptor-Based Response Headers: Uses interceptors to add CORS headers before method execution. This is a common approach but can be verbose.
- Spring MVC 4.2+ Built-in Support: The preferred method, leveraging Spring's native CORS configuration.
Spring MVC Configuration
Spring MVC 4.2 and later versions provide built-in CORS support. You can configure it directly in your Spring configuration file:
<!-- API cross-domain configuration -->
<mvc:cors>
<mvc:mapping path="/api/**"
allowed-origins="*"
allowed-methods="POST, GET, OPTIONS, DELETE, PUT"
allowed-headers="Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"
allow-credentials="true" />
</mvc:cors>
Alternatively, you can use the @CrossOrigin annotation on controllers for more granular control. For example:
@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "*", allowedHeaders = "*", methods = {RequestMethod.GET, RequestMethod.POST})
public class ApiController {
// Controller methods
}
Ensure your Spring MVC version is 4.2 or higher to use these features. For more details, refer to the official Spring blog post on CORS support.
By implementing CORS in Spring MVC, you enable secure and flexible cross-domain requests, enhancing the interoperability of your RESTful APIs with modern web applications.