一. 跨域环境介绍:
后端: servlet 实现, 使用过滤器让响应携带跨域响应信息(本问题和后端如何设置跨域响应头无任何关系);
运行地址: http://localhost:8080
前端: vue + axios(如果你使用原生ajax/fetch, 此方法也可行);
运行地址: http://localhost:9091
二. 代码环境:
1. CORSFilter过滤器代码:
@WebFilter("/*")
public class CORSFilter extends HttpFilter {
@Override
protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
System.out.println("跨域设置...");
//解决跨域问题
res.setHeader("Access-Control-Allow-Origin", "http://localhost:9091");
res.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
res.setHeader("Access-Control-Max-Age", "3600");
res.setHeader("Access-Control-Allow-Headers", "x-requested-with, Content-Type");
res.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(req, res);
}
}
2. 前端请求代码:
<template>
<div id="app">
<button @click="login">登录</button>
<button @click="getPageOne">获取第一页数据</button>
</div>
</template>
<script>
import axios from "axios";
export default {
name: "App",
components: {},
data() {
return {
userInfo: {
name: "admin",
password: "111111",
},
};
},
methods: {
async login() {
await axios
.post(
"http://localhost:8080/moveHouse/user/login?" + Date.now(),
JSON.stringify(this.userInfo)
)
.then((res) => {
console.log(res);
});
},
async getPageOne() {
await axios.get("http://localhost:8080/moveHouse/booking/selectPage?pageSize=2&pageNum=1").then(res => {
console.log(res);
})
}
},
};
</script>
<style>
</style>
三. 问题复现
请求login服务后, 响应中会返回cookie信息, 如下:
但是, 客户端并没有将cookie存进浏览器的本地cookie中, 如下:
四. 问题解决
几经周折(真的很周折), 终于解决了这个问题!
是什么原因导致客户端不存储cookie呢? 很显然就是客户端的问题? 在众多的帖子中我发现了原生ajax中XMLHttpRequest对象有一个withCredentials静态属性, MDN 这样介绍此属性:
绿色框描述表达的意思是: withCredentials 为false时, 客户端将不保存响应携带的cookie, 而且默认值还是false; 我醍醐灌顶!
Axios请求库, 就是根据原生ajax进行封装的, 所以axios也具备这样一个属性, 且和XMLHttpRequest的默认值一样,同样为false.
所以我在created钩子处,设置了axios的默认配置中的withCredentials属性为true: 如下:
再次发起登录请求, cookie已经存储到浏览器中, 如下:
提两点:
1. 如果不设置withCredentials为true, 那么请求同样不会携带浏览器存储的cookie到服务器, 尽管你的cookie是存在的; 比如说你使用原生ajax发请求, 只能局部设置withCredentials的时候, 很容易出现这样的情况-----能拿到cookie, 但是后续请求无法携带cookie, 那么你应该检查你的后续请求是否设置了"允许携带";
2. 我使用axios.defaults.withCredentials是在本Vue组件内设置生效了, 组件内方法所有的请求是可以生效的, 其他组件局部引入axios设置后才可行. 推荐全局引入, 省去不少麻烦;