運(yùn)行環(huán)境
操作系統(tǒng):Windows 10 十气;
開發(fā)工具:IDEA-2019.3;
Web服務(wù)器:Tomcat 9.0.24春霍;
JDK版本: jdk 1.8.0_221砸西;
Spring boot版本:2.0.9.RELEASE
開始
想起最早搭建spring boot框架的時(shí)候,就遇到了跨域的問題址儒。當(dāng)時(shí)芹枷,也嘗試去解決,雖然莲趣,最終解決了鸳慈,但是,總是感覺稀里糊涂的喧伞。
這次看了公眾號(hào)的文章《Cors跨域(一):深入理解跨域請求概念及其根因》走芋,又燃起了我嘗試重新梳理跨域問題的想法。
若想實(shí)現(xiàn)Cors機(jī)制的跨域請求潘鲫,是需要瀏覽器和服務(wù)器同時(shí)支持的翁逞。關(guān)于瀏覽器對CORS的支持情況:現(xiàn)在都2021年了,so可以認(rèn)為100%的瀏覽器都是支持的溉仑,再加上CORS的整個(gè)過程都由瀏覽器自動(dòng)完成挖函,前端無需做任何設(shè)置,所以前端工程師的ajax原來怎么用現(xiàn)在還是怎么用浊竟,它對前段開發(fā)人員是完全透明的怨喘。
我摘錄了文章的一段話,從上面可以看出來振定,B/S架構(gòu)下的項(xiàng)目哲思,前端我們不做任何修改,我們主要解決的后端的問題吩案。而后端的處理的目的也是為了讓前端知道后端是如何允許跨域請求的棚赔。
方法1. 使用Filter過濾器解決
這里不依賴spring boot。主要思路就是開發(fā)一個(gè)Filter,并讓Spring容器去掃描注冊靠益。
@Component
//filter雖然是servlet的三大組件之一丧肴,但是也是需要顯式的注冊在xml中的,后續(xù)servlet3.0后支持注解配置胧后,使用@componet注解芋浮,
//讓spring 去掃描filter,并注冊使用
public class CORSFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
HttpServletRequest request = (HttpServletRequest) servletRequest;
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", "content-type,Authorization");
response.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
方法2:配置FilterRegistrationBean
注意FilterRegistrationBean是spring boot框架提供的一個(gè)類壳快。這個(gè)類為我們注冊filter提供了便捷纸巷。我們要注冊的也是spring-web內(nèi)部提供的CorsFilter。
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean filterRegistrationBean(){
//跨域相關(guān)配置
Map<String, CorsConfiguration> corsConfigs = new LinkedHashMap<>();
corsConfigs.put("*", new CorsConfiguration().applyPermitDefaultValues());
corsConfigs.put("/**", new CorsConfiguration().applyPermitDefaultValues());
//組裝跨域ConfigurationSource
UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.setCorsConfigurations(corsConfigs);
//組裝CorsFilter
CorsFilter corsFilter = new CorsFilter(configSource);
//注冊filter
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(corsFilter);
registrationBean.addUrlPatterns("/*");
registrationBean.setName("corsFilter");
registrationBean.setOrder(1);
return registrationBean;
}
}
方法3:使用@CrossOrigin
使用@CrossOrigin眶痰,能夠更加細(xì)粒度的控制跨域請求瘤旨。
@CrossOrigin
@RequestMapping("/home")
public String home(Model model) {
return "home";
}
方法4:使用WebMvcConfigurer方式全局配置
使用spring mvc 提供的接口WebMvcConfigurer配置跨域。
@Configuration
public class WebSecurityConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
//該字段是必須的竖伯,用來列出瀏覽器的CORS請求會(huì)用到哪些HTTP方法存哲,
.allowedMethods("GET","POST","PUT","DELETE","OPTIONS")
//該字段是一個(gè)逗號(hào)分隔的字符串,指定瀏覽器CORS請求會(huì)額外發(fā)送的頭信息字段七婴,上例是X-Custom-Header祟偷。
.allowedHeaders("Access-Control-Allow-Origin","token","secret")
//CORS請求時(shí),XMLHttpRequest對象的getResponseHeader()方法只能拿到6個(gè)基本字段打厘。如果想拿到其他字段修肠,就必須在Access-Control-Expose-Headers里面指定。
//.exposedHeaders("token","secret")
.allowCredentials(true)//它的值是一個(gè)布爾值户盯,表示是否允許發(fā)送Cookie氛赐。默認(rèn)情況下,Cookie不包括在CORS請求之中
//該字段可選先舷,用來指定本次預(yù)檢請求的有效期,單位為秒
.maxAge(3600);
}
}
上面4中方法滓侍,第一種用了servlet的知識(shí)蒋川,第二種用了spring boot的知識(shí),第三種用了spring框架的細(xì)粒度控制注解撩笆,第四種是spring框架提供專門跨域解決方案捺球。
第一種最好理解,第四種是最優(yōu)雅解決方案夕冲。
總結(jié)
在解決這個(gè)問題的時(shí)候氮兵,由于涉及的知識(shí)塊很多。會(huì)遇到的宏觀問題有:
- 1.你不知道這是屬于spring框架的歹鱼,spring boot的泣栈,還是servlet的。
- 2.這是幾個(gè)知識(shí)塊組合才能解決的。
- 3.可以從任意一個(gè)知識(shí)塊的角度出發(fā)都可以解決這個(gè)問題南片,條條大路通羅馬掺涛。
你在解決這個(gè)問題之前,這3個(gè)問題始終都會(huì)纏繞在一起疼进,讓人禿頭薪缆。等回頭看,這3個(gè)問題都有三個(gè)正確的答案伞广。但是拣帽,我們又浪費(fèi)了很多的時(shí)間。
我從別人身上學(xué)到一個(gè)優(yōu)點(diǎn)嚼锄,就是减拭,以解決問題為導(dǎo)向。最重要的灾票,是先要解決問題峡谊,不要管解決的方案是不是很啰嗦,是不是不優(yōu)雅刊苍。只有解決了問題既们,才能回過頭剖析問題,優(yōu)化方案正什。