使用拦截器解决跨域问题
1.跨域
**跨域问题(CORS)是指在浏览器中,当一个网页向不同域名(域、协议或端口)**发送请求时,如果目标资源的响应未包含适当的跨域头信息,浏览器会阻止该请求,以保护用户数据的安全。
**同源策略(Same-Origin Policy)**是浏览器的一项安全机制,它限制了一个网页只能从同一来源加载其他资源,即源自相同协议、域名和端口的资源。这种限制是为了防止恶意网站通过跨域请求获取用户的敏感信息。
当网页需要从其他域名请求数据时(例如通过 AJAX 请求或通过
<img>
、<script>
等标签加载资源),浏览器会发送一个跨域请求。这时,浏览器会向目标服务器发送一个预检请求(OPTIONS 请求)来获取服务器是否允许跨域访问的权限。如果服务器响应中包含了适当的跨域头信息(如 Access-Control-Allow-Origin),浏览器会允许请求继续并获取响应数据。否则,浏览器将拦截该请求,JavaScript 代码将无法访问响应数据。
2.解决办法
解决跨域问题的常见方法包括:
- 在服务器端设置适当的跨域头信息,允许指定的域名进行跨域访问。
- 使用代理服务器,将跨域请求发送到同一域名下,然后由代理服务器转发请求并返回响应。
- 使用 JSONP(JSON with Padding)来进行跨域请求,JSONP 利用
<script>
标签不受同源策略限制的特性来获取跨域数据。- 使用 WebSocket 进行双向通信,WebSocket 不受同源策略的限制。
- 在某些情况下,使用跨域资源共享(CORS)的凭证(Credentials)模式,可以发送包含凭证的跨域请求。
需要注意的是,跨域问题只存在于浏览器环境中,服务器之间的通信不受同源策略的限制。
3.使用拦截器解决跨域问题
3.1 方案一
3.1.1定义拦截器
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
public class MyInteceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String origin = request.getHeader("Origin");
log.info("origin: {}", origin);
response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD");
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization,Access-Token,token");
response.setHeader("Access-Control-Expose-Headers", "*");//响应客户端的头部 允许携带Token 等等
response.setHeader("Access-Control-Allow-Credentials", "true"); // 允许携带cookie
response.setHeader("Access-Control-Max-Age", "3600"); // 预检请求的结果缓存时间
return true;
}
}
3.1.2 注册拦截器
package com.lhc.config;
import com.lhc.interceptors.MyInteceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInteceptor()).excludePathPatterns("/webjars/**", "/swagger-resources/**", "/doc.html").addPathPatterns("/**");
}
}
3.2 方案二
3.2.1定义拦截器
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
public class MyInteceptor implements HandlerInterceptor {
}
3.2.2 配置跨域资源共享(CORS)的映射规则
import com.lhc.interceptors.MyInteceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*") //2.4.0版本后的写法
.allowCredentials(true)
.allowedMethods("*")
.allowedHeaders("*");
}
}
3.2.3 报错
java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*"since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
解决方案
SpringBoot升级到2.4.0版本之后,跨域配置中的
.allowedOrigins
不再可用,需要修改为:.allowedOriginPatterns