在Java项目中实现跨域资源共享(CORS)
在现代Web开发中,前后端分离的架构已经变得非常普遍。在这种架构中,前端和后端通常运行在不同的域名或端口下,这就带来了跨域请求的问题。为了安全性,浏览器默认禁止跨域请求,但我们可以通过设置跨域资源共享(CORS,Cross-Origin Resource Sharing)来允许特定的跨域请求。本文将介绍如何在Java项目中实现CORS。
1. CORS概述
CORS是一个W3C标准,它允许服务器指示哪些跨域请求是被允许的。CORS通过增加HTTP头来告知浏览器,某些请求是被允许的。常用的CORS头包括:
Access-Control-Allow-Origin
:指定允许访问的源。Access-Control-Allow-Methods
:指定允许的HTTP方法。Access-Control-Allow-Headers
:指定允许的请求头。Access-Control-Allow-Credentials
:是否允许发送Cookie。Access-Control-Max-Age
:预检请求的缓存时间。
2. 在Spring Boot中实现CORS
Spring Boot是一个流行的Java框架,提供了多种方式来实现CORS。下面介绍几种常见的方法。
2.1 在控制器上设置CORS
我们可以在控制器的方法或类上使用@CrossOrigin
注解来设置CORS。
示例代码:
package cn.juwatech.controller; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @CrossOrigin(origins = "http://example.com") @GetMapping("/hello") public String hello() { return "Hello, World!"; } }
在上述代码中,我们在hello
方法上添加了@CrossOrigin
注解,指定允许来自http://example.com
的跨域请求。
2.2 全局配置CORS
如果需要对所有请求启用CORS,可以通过全局配置来实现。
示例代码:
package cn.juwatech.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("http://example.com") .allowedMethods("GET", "POST", "PUT", "DELETE") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }; } }
在上述代码中,我们通过实现WebMvcConfigurer
接口的addCorsMappings
方法,全局配置了CORS。
2.3 使用过滤器配置CORS
除了使用注解和全局配置外,还可以通过过滤器来配置CORS。
示例代码:
package cn.juwatech.filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CORSFilter extends HttpFilter { @Override public void init(FilterConfig filterConfig) throws ServletException { // 初始化代码 } @Override protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { response.setHeader("Access-Control-Allow-Origin", "http://example.com"); response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE"); response.setHeader("Access-Control-Allow-Headers", "*"); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Max-Age", "3600"); chain.doFilter(request, response); } @Override public void destroy() { // 销毁代码 } }
注册过滤器:
package cn.juwatech.config; import cn.juwatech.filter.CORSFilter; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FilterConfig { @Bean public FilterRegistrationBean<CORSFilter> corsFilter() { FilterRegistrationBean<CORSFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new CORSFilter()); registrationBean.addUrlPatterns("/*"); return registrationBean; } } • 1
在上述代码中,我们定义了一个CORS过滤器,并通过FilterRegistrationBean
将其注册到Spring Boot应用中。
3. 处理复杂请求
浏览器在发送某些复杂请求(如PUT
、DELETE
请求或带有自定义头部的请求)之前,会先发送一个预检请求(OPTIONS
请求)。服务器需要响应预检请求以告知浏览器是否允许实际请求。
示例代码:
package cn.juwatech.config; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CORSFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { response.setHeader("Access-Control-Allow-Origin", "http://example.com"); response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); response.setHeader("Access-Control-Allow-Headers", "*"); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Max-Age", "3600"); if (RequestMethod.OPTIONS.name().equalsIgnoreCase(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); } else { filterChain.doFilter(request, response); } } }
在上述代码中,我们扩展了OncePerRequestFilter
,并在OPTIONS
请求时返回200 OK
状态码,从而处理预检请求。
总结
在Java项目中实现跨域资源共享(CORS)是解决前后端分离架构中跨域请求问题的重要手段。通过使用Spring Boot提供的注解、全局配置和过滤器等方式,我们可以灵活地配置CORS,确保应用的安全性和跨域请求的正常处理。希望通过本文的介绍,大家能够更好地理解和实现CORS,从而优化Java Web应用的开发和部署。