最近使用spring cloud框架进行前后端分离开发,因为我们是通过网关去访问后台接口,ip
、端口都相同,所以没有出现过跨域问题,但是前端的同事把项目用webstrom打开以后(端口和ip就成了webstrom分配的)就有了跨域问题无法请求到后台,浏览器报"CORS 头缺少 'Access-Control-Allow-Origin'",但是我们已经在网关里设置了Access-Control-Allow-Origin为*,代码如下:
@Service
public class AuthFilter extends ZuulFilter {
/**
* 日志对象
*/
private static final Logger logger = LoggerFactory.getLogger(AuthFilter.class);
@Autowired
private FilterConfig filterConfig;
/**
* redis缓存
*/
@Autowired
private RedisService redisService;
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
HttpServletResponse response = ctx.getResponse();
//解决浏览器跨域问题
response.addHeader("Access-Control-Allow-Origin", "*");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// response.addHeader("Access-Control-Allow-Credentials", "true");
// response.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH");
// response.addHeader("Access-Control-Max-Age", "3600");
// response.addHeader("Vary", "Origin");
response.addHeader("Access-Control-Allow-Headers", "token,accesstoken,Content-type");
//请求接口URL时登录token有效性校验
return null;
}
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
}
对此我在本地随便写了个小项目还原了当时的情景,我把代码以及报错贴出来麻烦各位看一下哪里有不对的;
前端代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script src="js/jquery-1.9.1.min.js"></script>
</head>
<script>
function t1(){
$.ajax({
url:'http://localhost:9001/xzw/say',
type:'post',
contentType : 'application/json;charset=utf-8',
dataType:'json',
data : JSON.stringify({
batch_id : 'ncveirugheasolvgil'
}),
success : function(data){
alert('成功跨域');
alert(data);
},
error : function(){
alert('error');
}
})
}
</script>
<body>
<input type="button" value="测试跨域是否能获取数据" onclick="t1()"/>
</body>
</html>
后台代码:
@RestController
@RequestMapping("/xzw")
public class PageDemoController {
@RequestMapping("/say")
public String say(HttpServletRequest request,HttpServletResponse response,@RequestParam(value="batch_id")String batch_id){
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.addHeader("Access-Control-Allow-Headers", "*");
System.out.println("batch_id="+batch_id);
return "hello world";
}
}
浏览器报错
已拦截跨源请求:同源策略禁止读取位于 http://localhost:9001/xzw/say 的远程资源。(原因:CORS 头缺少 'Access-Control-Allow-Origin')。[详细了解]
已拦截跨源请求:同源策略禁止读取位于 http://localhost:9001/xzw/say 的远程资源。(原因:CORS 请求未能成功)。[详细了解]
我们项目里的拦截器原本除了设置Access-Control-Allow-Origin还有验证token的代码,前端如果先进行登陆然后在ajax请求的时候把token拿到放在header里就不会有跨域问题,我把token验证的代码去掉了就出现了跨域问题,但是我看验证token的逻辑判断对跨域没有什么特殊的处理,一下为拦截器原代码:
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
HttpServletResponse response = ctx.getResponse();
//解决浏览器跨域问题
response.addHeader("Access-Control-Allow-Origin", "*");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
// response.addHeader("Access-Control-Allow-Credentials", "true");
// response.addHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH");
// response.addHeader("Access-Control-Max-Age", "3600");
// response.addHeader("Vary", "Origin");
response.addHeader("Access-Control-Allow-Headers", "token,accesstoken,Content-type");
//请求接口URL时登录token有效性校验
Object token = request.getHeader("token");
if(token==null||token.equals("")) {
token = null;
}
boolean flag = false;//请求路径是否在过滤范围标识
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
ctx.setSendZuulResponse(false);
return null;
}
String ignores = filterConfig.getIgnores();
if(!StringUtilHelper.isEmpty(ignores)) {
String[] ignores_arr = ignores.split(",");
for(String ignore:ignores_arr) {
if(request.getRequestURI().toString().contains(ignore)) {
//无需token校验
flag = true;
break;
}
}
}
logger.info("网关日志:method={}, uri={},result={},token={}",request.getMethod(), request.getRequestURI(), (true==flag?"无需token校验":"需要token校验"),token);
if(!flag) {
//需要校验token有效性
if(token==null) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(HttpServletResponse.SC_UNAUTHORIZED);
ctx.setResponseBody("token为空,未认证用户");
return null;
} else {
//redis校验
if(redisService.check(token.toString())!=ServiceConstants.STATE_1) {
ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(HttpServletResponse.SC_UNAUTHORIZED);
ctx.setResponseBody("token超时,请重新登录");
return null;
}
}
}
return null;
}