1. 前言
什么是跨域?
当你在浏览器中,从一个域名的网页去请求另一个域名的资源时,域名/端口/协议任意一个不同,都是称之为跨域访问。
为什么会出现跨域现象?
这是由于浏览器的同源策略,即网站A只能访问网站A本身的内容,不能访问网站B的内容。
那么问题来了,既然跨域是浏览器的问题导致的,为啥我们需要修改后台程序呢?
2. 跨域的判定流程
浏览器和服务器的合作判定步骤如下:
- 浏览器先根据同源策略对前端页面和后台交互地址做匹配,若同源,则直接发送数据请求;若不同源,则发送跨域请求。
- 服务器解析程序收到浏览器跨域请求后,根据自身配置返回对应文件头。若未配置过任何允许跨域,则文件头里不包含Access-Control-Allow-origin字段,若配置过域名,则返回Access-Control-Allow-origin+ 对应配置规则里的域名的方式。
- 浏览器根据接收到的http文件头里的Access-Control-Allow-origin字段做匹配,若无该字段,说明不允许跨域;若有该字段,则对字段内容和当前域名做比对,如果同源,则说明可以跨域,浏览器发送该请求;若不同源,则说明该域名不可跨域,不发送请求
我们可以看到,浏览器是根据请求头指定跨域的信息来判定是否可以访问跨域信息的。
那么我们就可以通过修改后台返回的请求头,来实现跨越的访问。
3. SpringBoot中实现跨域访问
3.1. 方式一 使用@CrossOrigin注解
Spring 已经为我们想好了解决方案,我们可以直接使用。那就是@CrossOrigin注解。
使用该注解可以使用在Controller 的类上或者方法上,这样可以方便地实现局部的跨域请求。
如下例:
@CrossOrigin
@RestController
public class TestController {
}
3.2. 方式二 继承WebMvcConfigurerAdapter 类
早期的SpringBoot版本中(1.5版本以前),我们需要通过继承WebMvcConfigurerAdapter 类,然后重写抽象方法来实现跨域:
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedHeaders("*")
.allowedMethods("*")
.allowedOrigins("*")
.allowCredentials(true);
}
}
3.3. 方式三 实现WebMvcConfigurer 接口
SpringBoot 2.X 以后的版本中,我们需要通过实现WebMvcConfigurer 接口来实现跨域:
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedHeaders("Content-Type","X-Requested-With","accept,Origin","Access-Control-Request-Method","Access-Control-Request-Headers","token")
.allowedMethods("*")
.allowedOrigins("*")
.allowCredentials(true);
}
}
3.4. 方式四 通过拦截器实现
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.addHeader("Access-Control-Allow-Headers",
"Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,token");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
});
}
}
3.5. 方式五使用servlet的过滤器实现
@Component
@WebFilter(urlPatterns = {"/*"}, filterName = "crossOriginFilter")
public class TokenAuthorFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse rep = (HttpServletResponse) response;
HttpSession session = req.getSession();
//设置允许跨域的配置
// 这里填写你允许进行跨域的主机ip(正式上线时可以动态配置具体允许的域名和IP)
rep.setHeader("Access-Control-Allow-Origin", "*");
rep.setHeader("Access-Control-Expose-Headers", jwtProperties.getHeader());
// 允许的访问方法
rep.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH");
// Access-Control-Max-Age 用于 CORS 相关配置的缓存
rep.setHeader("Access-Control-Max-Age", "3600");
rep.setHeader("Access-Control-Allow-Headers", "token, Origin, X-Requested-With, Content-Type, Accept");
//若要返回cookie、携带seesion等信息则将此项设置我true
rep.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(req, rep);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
4. 小结
本节教程中我们了解了什么是跨域,以及跨域是如何产生的,最后我们给出了跨越的后台解决方案和实现方式。
本文暂时没有评论,来添加一个吧(●'◡'●)