说明
新版Chrome浏览器导致 cookie 跨域失败,详见:cookie跨域失败-新版chrome浏览器SameSite属性
本文适用 简单请求 携带 cookie,非简单请求 携带 cookie
原因详见 链接
filter 过滤器
关键代码
Access-Control-Allow-Origin 头
允许可访问的域列表,携带cookie时,不能是 *
,必须前端服务器域名,而且末尾不能有符号: /
,如下:
response.setHeader("Access-Control-Allow-Origin", "http://localhost:9528");
Access-Control-Allow-Headers 头
携带cookie时,不能是 *
,如下:
response.setHeader("Access-Control-Allow-Headers", "access-control-allow-origin, authority, content-type, version-info, X-Requested-With");
解释:
X-Requested-With
:前端发请求可以携带X-Requested-With
,后端用来判断是否 ajax 请求。如果前端使用 axios,默认不携带该头,需要额外指定,详见 链接
Access-Control-Allow-Credentials 头
允许浏览器发送 cookie
response.setHeader("Access-Control-Allow-Credentials", "true");
完整代码
package com.zrgj.epidemic.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter("/*")
public class CORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
// response.setHeader("Access-Control-Allow-Origin", "*");//允许可访问的域列表
//允许可访问的域列表,携带cookie时,不能是 *,必须填域名,而且末尾不能有符号: /
response.setHeader("Access-Control-Allow-Origin", "http://localhost:9528");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, HEAD, PUT");
response.setHeader("Access-Control-Max-Age", "3600");//设置 Preflight 请求缓存多长时间(以秒为单位)。
//携带cookie时,不能是 *
response.setHeader("Access-Control-Allow-Headers", "access-control-allow-origin, authority, content-type, version-info, X-Requested-With");
// response.setHeader("Access-Control-Allow-Headers", "*");
//允许浏览器发送 cookie
response.setHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
注解配置
如果使用注解启用过滤器,加上下面注解:
@WebFilter("/*")
web.xml 配置
如果使用 web.xml
配置启用过滤器,加上下面配置:
<filter>
<filter-name>CORSFilter</filter-name>
<filter-class>top.malaoshi.filter.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CORSFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
ajax
jquery
$.ajax({
url:baseUrl+'goods/list',
type:'post',
dataType:'json',//服务器端返回的数据格式是json
xhrFields: { //带上cookie
withCredentials: true
},
data: {
"status":1
},//发给服务器端的数据
success:function(res){ //data:服务器端返回给浏览器端的数据
if(res.code==0){
console.log(res)
}else{
alert(res.msg);
}
},
error:function (XMLHttpRequest, textStatus, errorThrown) {
alert(XMLHttpRequest);
alert(textStatus);
alert(errorThrown);
}
});
axios 非简单请求
axios 发送post请求,默认是 application/json
,所以是 非简单请求
// 携带 cookie
axios.defaults.withCredentials = true;
// 携带 X-Requested-With
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
axios.post('http://localhost:8080/login',
{
"username":this.loginForm.username,
"password":this.loginForm.password
}
)
.then((res) => {
console.log(res);
this.loading = false
})
.catch(function (error) {// 请求失败处理
console.log(error);
});
axios 简单请求
get 请求携带 cookie:
axios.defaults.withCredentials = true;//带cookie
axios.get(baseUrl+'goods/list?status=1').then(function(res){
console.log(res.data);
})
get 请求携带 cookie 的另一种方式:
axios.get(
baseUrl+'goods/list?status=1',
{withCredentials: true}//带cookie
).then(function(res){
console.log(res.data);
})