Marvin's Blog

Hi, My friend. Welcome to my space

0%

Http Cross

Http跨域请求及HttpSession同步终极手册

后端配置

继承org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport或者实现javax.servlet.Filter接口两种方式,springboot2.0以上才有WebMvcConfigurationSupport,之前为WebMvcConfigurerAdapter

实现Filter接口后跨域配置的核心代码如下,其中HttpSession同步的重点在于response.setHeader("Access-Control-Allow-Credentials", "true");

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {

HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;

String[] allowDomain = {"http://127.0.0.1:8848", "http://localhost:8848"};
Set<String> allowedOrigins = new HashSet<String>(Arrays.asList(allowDomain));
log.info("{}", request.getRequestURI());
String originHeader = request.getHeader("Origin");
// response.setHeader("Access-Control-Allow-Origin",request.getHeader("Origin"));
//注意重点:Access-Control-Allow-Origin不可以写*通配,需要明确写出请求方的IP地址及端口
if (allowedOrigins.contains(originHeader)) {
response.setHeader("Access-Control-Allow-Origin", originHeader);
//HttpSession同步重点,允许携带Cookie
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
}
filterChain.doFilter(servletRequest, servletResponse);
}

继承WebMvcConfigurationSupport后,跨域配置应当重写addCorsMappings,同步HttpSession的重点在于allowCredentials(true)

1
2
3
4
5
6
7
8
9
@Override
protected void _addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 允许跨域访问的路径
.allowedOrigins("")//允许跨域访问的源
.allowedMethods("")//允许请求方法
.allowedHeaders("")//允许头部设置
.allowCredentials(true)//允许请求携带Cookie
.maxAge(3600);//是否发送cookie,预检间隔时间
}

继承WebMvcConfigurationSupport后,同时可以配置拦截器,其中自定义拦截器MyInterceptor需要实现接口HandlerInterceptor

1
2
3
4
5
6
@Override
public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(new TestInterceptor()).addPathPatterns("/**"); // /**下的每一个接口都要有"登录"的校验
registry.addInterceptor(new MyInterceptor()).addPathPatterns("/interceptor/test");//mes下的接口都要被拦截
super.addInterceptors(registry);
}

前端请求

前端请求代码如下,根据前端框架配置可能有所不同,但是HttpSession同步的关键在于xhrFields: {withCredentials: true},既为允许Http请求携带Cookie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$.ajax({
// 同步请求是为让WebSocket连接之前可以从配置中拿到HttpSession
async:false,
url: 'http://192.168.1.10:9119/session/test',
data: {
value: 'admin',
key: "123456",
},
// 下列两项配置为跨域请求HttpSession同步的关键,允许Http请求携带Cookie
xhrFields: {
withCredentials: true
},
crossDomain: true,
success: function(data) {
// setCookie(data.name,data.value,data.time/1000);
console.log(data)
}
});

浏览器设置

重点:以上配置全部正确无误后,HttpSession还是不能同步,这是因为浏览器限制。

ChromeEdgd配置相似,因为同核。其它浏览器有待研究

  1. 在地址栏输入chrome://flagsedge://flags
  2. 搜索cookies
  3. 禁用下列两项
    • SameSite by default cookies = Disabled
    • Cookies without SameSite must be secure = Disabled

至止,前后端分离跨域请求HttpSession同步实现成功。