1. 引言
我們在開發過程中通常因爲不同應用之間的接口調用或者應用之間接口集成時經常會遇到跨域問題, 導致無法正常獲取接口數據,那麼什麼是跨域? 跨域的解決辦法是什麼? 下面結合Spring Boot相關的項目應用實戰, 詳解說明跨域的解決方案。
1.1 什麼是跨域(CORS)
跨域(CORS)是指不同域名之間相互訪問。跨域,指的是瀏覽器不能執行其他網站的腳本,它是由瀏覽器的同源策略所造成的,是瀏覽器對於JavaScript所定義的安全限制策略。
也就是如果在A網站中,我們希望使用Ajax來獲得B網站中的特定內容,如果A網站與B網站不在同一個域中,那麼就出現了跨域訪問問題。
同域:
- 同一協議, 如http或https
- 同一IP地址, 如192.168.1.2
- 同一端口, 如8080
以上三個條件中有一個條件不同就會產生 跨域問題。
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)
說明: 除此之外還有其他的跨域解決方案, 在這裏我只是介紹了幾種在實際工作中的解決方案。
下面, 我將結合在實際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);
}
}
以上爲相關項目實戰中的應用總結, 如有不當之處, 請指正。