xuziwen127 2019-01-17 22:46 采纳率: 55.6%
浏览 11958
已采纳

spring boot设置了Access-Control-Allow-Origin还是有跨域问题

最近使用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;
    }
  • 写回答

8条回答 默认 最新

  • //Q 2019-01-18 17:52
    关注

    在 你的AuthFilter 里面把shouldFilter() 替换成这个

    @Override
        public boolean shouldFilter() {
            RequestContext ctx = RequestContext.getCurrentContext();
            HttpServletRequest request = ctx.getRequest();
                    HttpServletResponse response = ctx.getResponse();
            if("OPTIONS".equals(request.getMethod())){
                //过滤该请求,不往下级服务去转发请求,到此结束  
                ctx.setSendZuulResponse(false); 
                ctx.setResponseStatusCode(200);  
                ctx.getResponse().setContentType("text/html;charset=UTF-8");
                ctx.setResponseBody("true");
                                response.setHeader("Access-Control-Allow-Origin", "*");
                                response.setHeader("Access-Control-Allow-Credentials", "true");
                                response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH");
                                response.setHeader("Access-Control-Max-Age", "3600");
                                response.addHeader("Access-Control-Allow-Headers", "token,accesstoken,Content-type");
                return false;
            }
            return true;
        }
    
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(7条)

报告相同问题?

悬赏问题

  • ¥15 fluent的在模拟压强时使用希望得到一些建议
  • ¥15 STM32驱动继电器
  • ¥15 Windows server update services
  • ¥15 关于#c语言#的问题:我现在在做一个墨水屏设计,2.9英寸的小屏怎么换4.2英寸大屏
  • ¥15 模糊pid与pid仿真结果几乎一样
  • ¥15 java的GUI的运用
  • ¥15 Web.config连不上数据库
  • ¥15 我想付费需要AKM公司DSP开发资料及相关开发。
  • ¥15 怎么配置广告联盟瀑布流
  • ¥15 Rstudio 保存代码闪退