springboot 前后端分离开发解决跨域访问

  最近新学习了Java EE开发框架springboot,我在使用springboot前后台分离开发的过程中遇到了跨域求问题。在网上寻找答案的过程中发现网上的解决方案大多比较零散,我在这里整理一个解决方案,但未必是最好的方案。

  要在项目中解决跨域访问,需要解决三个问题:

  1. 服务器需要接受不同域的浏览器的请求
  2. 浏览器允许读取不同域的服务器的响应数据
  3. 保证浏览器每次访问的session是一致的

  第一个问题,服务器接受不同域的浏览器的请求,这是后台开发人员需要解决的问题。具体的解决方案有几种,我这里只总结了在springboot中使用cors协议的解决方案。其实即使是springboot中cors协议解决方案也分几种不同的解决方法,下面有一种的代码,就是生成一个org.springframework.web.servlet.config.annotation.WebMvcConfigurer接口的实例对象,并且将它纳入到spring容器中。这是一个全局的方法,比较方便,当然可以为局部请求设置允许跨域访问,这里不介绍。

示例代码:

import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class CreateBean {
    
    @Bean
    public WebMvcConfigurer corsConfigurer(){
        WebMvcConfigurer configurer = new WebMvcConfigurer(){

            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/**")
                .allowedOrigins("http://127.0.0.1:8020")
                .allowedMethods("GET", "POST", "DELETE", "PUT", "OPTIONS")
                .allowCredentials(true).maxAge(3600);
            }
            
        };
        return configurer;
    }
}

代码中的registry.addMapping("/**")表示所有的请求路径都可以跨域访问。allowedOrigins("http://xxx.com:xx")代表接收的请求的原服务器地址,这个方法的参数是可变参数,可以设置多个源服务器,如果允许所有,可以使用“*”代替(但是不推荐这么写)。

  解决第一个问题,那么服务器这关就通过了。但是B/S架构的web应用除了服务器,还有浏览器。在浏览器中有一个同源访问策略(火狐和谷歌都有,不知道其他的浏览器有没有),这里策略有可能禁止读取跨域访问的响应数据。其实在springboot中解决这个问题还是很简单的,只需要设置allowedOrigins()为具体的服务器地址,也就是不使用“*”代替,然后设置allowCredentials(true)就可以了

  第三个问题,解决session问题。在跨域请求中,每次请求传递给服务器的sessionid是不同的,这就造成了在服务器每次都给浏览器创建一个session,所以服务器不能获取session中存放的数据,为了解决这个问题,使用jQuery的解决访问时在options参数中添加字段xhrFields:{withCredentials:true}:

    $.ajax({
                    method:"post",
                    url:basePath+"user/login",
                    data:{
                        username:login.username,
                        password:login.password,
                        validateCode:login.validatecode
                    },
                    xhrFields:{
                        withCredentials:true
                    },
                    success:function(res){
                        console.log(res)
                        alert(res.message)
                    },
                    error:function(error){
                        alert(error)
                        console.log(error)
                    }
                })