大家都知道spring boot 可以通过@crossorigin实现跨域。但是在spring cloud 里,如果要粒度那么细的去控制跨域,这个就太繁琐了,所以一般来说,会在路由zuul里实现。
第一种方式:corsfilter在zuul服务下添加一个corsfilter实现跨域,实现起来方便。代码如下
@configurationpublic class gatewaycorsconfig {   @bean    public filterregistrationbean corsfilter() {        final urlbasedcorsconfigurationsource source = new urlbasedcorsconfigurationsource();        final corsconfiguration config = new corsconfiguration();        config.setallowcredentials(true);        config.addallowedorigin("*");        config.addallowedheader("*");        config.addallowedmethod("*");        //这个请求头在https中会出现,但是有点问题,下面我会说        //config.addexposedheader("x-forwared-port, x-forwarded-host");         source.registercorsconfiguration("/**", config);        filterregistrationbean bean = new filterregistrationbean(new corsfilter(source));        bean.setorder(ordered.highest_precedence);        return bean;    }}
经过测试,这样的配置在http的情况下跨域是ok的,但是当我的环境切换的https的情况下就发生了奇怪的问题。说明一下我遇到的问题。
前端 服务a 和 后端服务b 在同一台服务器上,服务a 调用 服务b 时,服务a通过负载均衡进入服务b时:
http时,服务a的请求跨域成功,https时,服务a的请求跨域失败。
也就是端口为443的时候,会被认为跨域失败!!
我一开始对比了请求头,以为是少了exposedheader的"x-forwared-port, x-forwarded-host",但是添加后,还是失败。因为急着上线,所以我没有去深入测试到底什么原因引起的https请求跨域失败。(所以如果大家发现我哪里写的不对,请务必通知我,让我也明白为什么失败!谢谢!)
第二种方式:继承zuulfilter因为第一种方式在https下失败后,我尝试了用zuulfilter实现cors的方式
一共需要两个filiter:一个pre, 一个post
pre-filter:
@componentpublic class firstfilter extends zuulfilter {    private logger logger = loggerfactory.getlogger(firstfilter.class);    @override    public string filtertype() {        /*        pre:可以在请求被路由之前调用        route:在路由请求时候被调用        post:在route和error过滤器之后被调用        error:处理请求时发生错误时被调用        * */        // 前置过滤器        return filterconstants.pre_type;    }    @override    public int filterorder() {        //// 优先级为0,数字越大,优先级越低        return 0;    }    @override    public boolean shouldfilter() {        requestcontext ctx = requestcontext.getcurrentcontext();        httpservletrequest request = ctx.getrequest();        //只过滤options 请求        if(request.getmethod().equals(requestmethod.options.name())){            return true;        }        return false;    }    @override    public object run() {        logger.debug("*****************firstfilter run start*****************");        requestcontext ctx = requestcontext.getcurrentcontext();        httpservletresponse response = ctx.getresponse();        httpservletrequest request = ctx.getrequest();        response.setheader("access-control-allow-origin",request.getheader("origin"));        response.setheader("access-control-allow-credentials","true");        response.setheader("access-control-allow-headers","authorization, content-type");        response.setheader("access-control-allow-methods","post,get");        response.setheader("access-control-expose-headers","x-forwared-port, x-forwarded-host");        response.setheader("vary","origin,access-control-request-method,access-control-request-headers");        //不再路由        ctx.setsendzuulresponse(false);        ctx.setresponsestatuscode(200);        logger.debug("*****************firstfilter run end*****************");        return null;    }}
pre-filter 用来处理预处理options请求,当发现是options请求的时候,给出跨域响应头,并且不对其进行zuul路由,直接返回成功(200), 给前端服务允许跨域
post-filter :
@componentpublic class postfilter extends zuulfilter {    private logger logger = loggerfactory.getlogger(postfilter.class);    @override    public string filtertype() {        /*        pre:可以在请求被路由之前调用        route:在路由请求时候被调用        post:在route和error过滤器之后被调用        error:处理请求时发生错误时被调用        * */        // 前置过滤器        return filterconstants.post_type;    }    @override    public int filterorder() {        //// 优先级为0,数字越大,优先级越低        return 2;    }    @override    public boolean shouldfilter() {        requestcontext ctx = requestcontext.getcurrentcontext();        httpservletrequest request = ctx.getrequest();        //过滤各种post请求        if(request.getmethod().equals(requestmethod.options.name())){            return false;        }        return true;    }    @override    public object run() {        logger.debug("*****************postfilter run start*****************");        requestcontext ctx = requestcontext.getcurrentcontext();        httpservletresponse response = ctx.getresponse();        httpservletrequest request = ctx.getrequest();        response.setheader("access-control-allow-origin",request.getheader("origin"));        response.setheader("access-control-allow-credentials","true");        response.setheader("access-control-expose-headers","x-forwared-port, x-forwarded-host");        response.setheader("vary","origin,access-control-request-method,access-control-request-headers");        //允许继续路由        ctx.setsendzuulresponse(true);        ctx.setresponsestatuscode(200);        logger.debug("*****************postfilter run end*****************");        return null;    }}
post-filter 用来处理 预处理options以外的请求,对于正常的请求,不但要给出跨域请求头,还需要允许请求进行路由(否则你的请求到这儿就结束啦),然后返回状态码200。(emmmm……这里要不要返回200,我觉得可能还要想一想……)
按照以上方式配置的话,方法一出现的问题,就得到了解决。服务a能够正常请求服务b了
虽然是正常实现了需求,但是感觉还是存在很多疑惑,希望大家看到的话,能给我指出不足。一起讨论!
相关文章:
跨域解决方案一:使用cors实现跨域_html/css_web-itnose
用cors实现webapi ajax跨域请求的方法
请求跨域解决方法cors
以上就是zuul实现cors跨域的两种方式:corsfilter、继承zuulfilter的详细内容。
   
 
   