原文链接:https://www.jianshu.com/p/e102fd47150b
本文主要记录了如何使用SpringBoot2.0配置CORS实现跨域,来解决前(Vue)后(SpringBoot)分离中带来的跨域问题。并实现Session登录后允许携带Cookie来保持登录的状态。
** 主要内容: **
1.问题描述
2.配置跨域
3.允许携带Cookies
4.完整配置
在前后分离的项目中,前端项目往往和后端项目是分开开发。前端有自己的服务器来访问页面比如http://127.0.0.1:8080,然后通过网络库(Axios)来实现Ajax请求后端服务器http://127.0.0.1:8085来实现数据的展现。
比如:
import axios from 'axios';
//创建实例
const instance = axios.create({
baseURL: 'http://127.0.0.1:8085',
timeout: 10000
});
//发起请求
instance.post("/admin/login", Qs.stringify({loginName: admin, pass: 123456}), {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
此时就会报如下错误
Failed to load http://127.0.0.1:8085/admin/login: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8080' is therefore not allowed access.
这就是问题所在,下面我们配置SpringBoot的CORS来实现允许Ajax跨域。
@Configuration
public class CORSConf {
private static final Logger LOG = LoggerFactory.getLogger(CorsConfiguration.class);
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
if (LOG.isInfoEnabled()) {
LOG.info("初始化 CORSConfiguration 配置");
}
registry.addMapping("/**")
.allowedHeaders("*")
.allowedMethods("*")
.allowedOrigins("*");
}
};
}
}
在你的SpringBoot项目中加入如上配置即可,允许所有请求的、所有头、所有方法、所有原始链接跨域访问,当然也可以配置指定的信息跨域访问,这里配置所有。下面我们再试试请求效果。
重启后台服务器,重新请求,不会报错了。
{
"data":{
"pass":"admin123",
"loginName":"admin"
},
"message":"操作成功!",
"resultCode":"00000"
}
当服务端使用session来保存登录信息,传统的应用时,只需要登录一次,剩下的访问都不需要登录,因为Cookie里保存了JSESSIONID信息,后台根据JSESSIONID拿到已经登录的Session来判断用户是否需要重新登录。但是前后分离项目里似乎没管用。观察2次请求发现:
登录请求:
Request URL:http://127.0.0.1:8085/admin/login
Request Method:POST
Status Code:200
Remote Address:127.0.0.1:8085
Referrer Policy:no-referrer-when-downgrade
Response Headers
view source
Access-Control-Allow-Origin:*
Content-Length:112
Content-Type:application/json
Date:Tue, 28 Aug 2018 01:13:29 GMT
Set-Cookie:JSESSIONID=5BAB67B259B9F426A6B4DD51074725F6; Path=/; HttpOnly
Vary:Origin
Vary:Access-Control-Request-Method
Vary:Access-Control-Request-Headers
获取列表请求:
Request URL:http://127.0.0.1:8085/blog/category/list
Request Method:GET
Status Code:200
Remote Address:127.0.0.1:8085
Referrer Policy:no-referrer-when-downgrade
Response Headers
view source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:*
Access-Control-Allow-Methods:POST, GET, OPTIONS, DELETE, PUT, HEAD
Access-Control-Allow-Origin:http://127.0.0.1:8080
Content-Type:application/json; =;charset=utf-8
Date:Tue, 28 Aug 2018 01:13:29 GMT
Set-Cookie:JSESSIONID=030E930C2891EFEA0B56A9023AC8EF09; Path=/; HttpOnly
Transfer-Encoding:chunked
可以发现在Set-Cookie:里的JSESSIONID不是一致,那么这就是问题所在了,第二次请求的SESSION不是登录的SESSION,所以导致获取不到登录的用户信息。那么保证2次的JSESSIONID就可以解决问题了。
前端配置:
//创建实例
const instance = axios.create({
baseURL: 'http://127.0.0.1:8085',
timeout: 10000,
withCredentials: true // 允许跨域带上cookies
});
只需要加入withCredentials: true 就可以了
再次请求登录报如下错误:
Failed to load http://127.0.0.1:8085/admin/login: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. Origin 'http://127.0.0.1:8080' is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
这是因为前端设置了允许携带Cookie,但是后端没设置允许,所以后端也应该设置允许跨域带上cookie
registry.addMapping("/**")
.allowedHeaders("*")
.allowedMethods("*")
.allowedOrigins("*")
.allowCredentials(true);// 允许跨域带上cookies
这样就完美的解决了跨域请求并保持登录的状态了,可以愉快的开发了。
SpringBoot后端:
@Configuration
public class CORSConf {
private static final Logger LOG = LoggerFactory.getLogger(CorsConfiguration.class);
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
if (LOG.isInfoEnabled()) {
LOG.info("初始化 CORSConfiguration 配置");
}
registry.addMapping("/**")
.allowedHeaders("*")
.allowedMethods("*")
.allowedOrigins("*")
.allowCredentials(true);
}
};
}
}
前端(Axios)配置:
const instance = axios.create({
baseURL: 'http://127.0.0.1:8085',
timeout: 10000,
withCredentials: true // 运行跨域带上cookies
});