1. 引言
我們在開發過程中通常因為不同應用之間的接口調用或者應用之間接口集成時經常會遇到跨域問題, 導致無法正常獲取接口數據,那么什么是跨域? 跨域的解決辦法是什么? 下面結合Spring Boot相關的項目應用實戰, 詳解說明跨域的解決方案。
1.1 什么是跨域(CORS)
跨域(CORS)是指不同域名之間相互訪問。跨域,指的是瀏覽器不能執行其他網站的腳本,它是由瀏覽器的同源策略所造成的,是瀏覽器對於JavaScript所定義的安全限制策略。
也就是如果在A網站中,我們希望使用Ajax來獲得B網站中的特定內容,如果A網站與B網站不在同一個域中,那么就出現了跨域訪問問題。
1.2 跨域的解決方案
前端解決方案
- 使用JSONP方式實現跨域調用;
- 使用NodeJS服務器做為服務代理,前端發起請求到NodeJS服務器, NodeJS服務器代理轉發請求到后端服務器;
- 設置瀏覽器允許跨域訪問,如Chrome瀏覽器設置
--disable-web-security
屬性, 該方案僅適用於開發環境 下的開發調試。
后端解決方案
- 服務端設置Response Header(響應頭部)的Access-Control-Allow-Origin(Java開發中可以使用Filter進行設置);
- 在需要跨域訪問的類和方法中設置允許跨域訪問(如Spring中使用@CrossOrigin注解);
- 繼承使用Spring Web的CorsFilter(適用於Spring MVC、Spring Boot)
- 實現WebMvcConfigurer接口(適用於Spring Boot)
2. Spring Boot跨域配置
1. 使用Filter方式進行設置
使用Filter過濾器來過濾服務請求,向請求端設置Response Header(響應頭部)的Access-Control-Allow-Origin屬性聲明允許跨域訪問。
@WebFilter public class CorsFilter implements Filter { // 日志對象 private static Logger logger = LoggerFactory.getLogger(CorsFilter.class); @Override 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) { // something init } public void destroy() { // destroy something } }
2. 使用@CrossOrigin注解
使用@CrossOrigin注解聲明類和方法允許跨域訪問。
@RequestMapping(value = "/v1/users") @RestController @CrossOrigin public class UserController extends BaseController { @Autowired private UserService userService; @RequestMapping(method = RequestMethod.POST) @CrossOrigin @RequestBody public User create(@Validated User user) { return userService.save(user); } }
3. 繼承使用Spring Web中的CorsFilter
package com.garyond.hurricane.config; import org.springframework.stereotype.Component; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import java.util.Arrays; /** * 跨域訪問配置 * * @author Garyond */ @Component public class CustomCorsFilter extends CorsFilter { public CustomCorsFilter() { super(configurationSource()); } private static UrlBasedCorsConfigurationSource configurationSource() { CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("*"); config.addAllowedHeader("*"); config.setMaxAge(36000L); config.setAllowedMethods(Arrays.asList("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/v1/**", config); return source; } }
4. 實現WebMvcConfigurer接口
Spring Boot 2.0中已經廢棄WebMvcConfigurerAdapter類, 開發人員可以通過實現WebMvcConfigurer
接口實現相應的功能。
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 CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowCredentials(true) .allowedMethods("GET", "POST", "DELETE", "PUT","PATCH") .maxAge(3600); } }