前后端分离的项目肯定要使用网关,目前最流行的网关是GateWay,但部署这个网关的时候,跨域是个令人捉摸不透的问题.
在这里插入图片描述

可以看到上面这张图,如果出现这些信息,多半是跨域问题没解决了.
跨域问题出现的情况有很多:

  1. 首先是前后端分离的项目,如果你前端直接访问后端一个模块的某个controller,是访问不到的,这个时候@CrossOrigin这个注解标注在controller上是可以解决问题的.
  2. 如果你部署了GateWay,可以在网关处弄一个全局的过滤器去解决问题(记得将这些bean注入到容器中):
public CorsWebFilter corsFilter1() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        //允许携带cookie的地址进行跨域
        config.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new
                PathPatternParser());
        source.registerCorsConfiguration("/**", config);

        return new CorsWebFilter(source);
    }

上面这个是最通用的全局解法,在尚硅谷的在线教育网站就是用这个bean来做,而且谷粒商城也是这个bean,但是这个bean不是万能的,很多小伙伴用了这个bean还是出现了错误.
其次,在renren-fast这个后端项目中,还有一个解决跨域的bean:

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
            .allowedOrigins("*")
            .allowCredentials(true)
            .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
            .maxAge(3600);
    }
}

这个bean是通过springmvc来做的,用在单独的模块还好,但是用在网关却失效了,这是因为网关不是基于springmvc的,而是基于webflux去做的,所以这样肯定是失效的.

@Bean
public WebFilter corsFilter2() {
    return (ServerWebExchange ctx, WebFilterChain chain) -> {
        ServerHttpRequest request = ctx.getRequest();
        if (CorsUtils.isCorsRequest(request)) {
            HttpHeaders requestHeaders = request.getHeaders();
            ServerHttpResponse response = ctx.getResponse();
            HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
            HttpHeaders headers = response.getHeaders();
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
            headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
                    requestHeaders.getAccessControlRequestHeaders());
            if (requestMethod != null) {
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
            }
            headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
            headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
            if (request.getMethod() == HttpMethod.OPTIONS) {
                response.setStatusCode(HttpStatus.OK);
                return Mono.empty();
            }
        }
        return chain.filter(ctx);
    };
}

上面这个是通用的GateWay网关,与webflux的写法差不多,所以肯定是能行的.其中还有其他版本的写法:

public WebFilter corsFilter() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                ServerHttpResponse response = ctx.getResponse();
                HttpHeaders headers = response.getHeaders();
                headers.add("Access-Control-Allow-Origin", "*");
                headers.add("Access-Control-Allow-Methods", "*");
                headers.add("Access-Control-Max-Age", "18000L");
                headers.add("Access-Control-Allow-Headers", "*");
                headers.add("Access-Control-Expose-Headers", "*");
                headers.add("Access-Control-Allow-Credentials", "true");
                if (request.getMethod() == HttpMethod.OPTIONS||request.getMethod()==HttpMethod.GET) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }

上面这个版本是直接将参数手动写上去,如果版本不对应的话,也是不行的,所以最好使用最原始枚举的方式直接写进入.
如果还是不行,就去看看GateWay官方,看看你对应的版本的解法是怎么样的.
如果还是不行,肯定是要仔细检查,看看你是否那地方出了问题,推荐检查这些地方:

  1. 首先看路径是否转发正确,转发不正确如果你配置了跨域,还是会报跨域的问题.
  2. 看看你调用的链路中,是否有一些用到的服务器没有开启.
  3. 看看你的跨域是否重复了,如果是重复了,还是会报跨域的问题的,不过这些问题会说你跨了多次的情况,你看得懂就行.(比如,在谷粒商城这个renren-fast后端的时候,人家的开源后端也是有一份跨域bean的,记得注释掉,你自己的才能生效)

其次,最后,GateWay网关我们转发路径的时候,一般都是用lb://服务名去转发路径的,但是有时候这样子会失效,具体可能的原因是你的服务要依赖spring-cloud-starter-loadbanner,和open-feign的依赖.如果还是不行,目前没有发现解决办法,大概率是版本的问题,所以可以直接用地址转发.

小技巧: 整合人人的后端项目的时候,因为它的controller路径是有些乱的,但是我们在做GateWay网关转发的时候-Path不能直接写/**,所以我们可以在前端的访问路径中加上一个固定后缀就可以了,然后让其来匹配这个后缀,但这个时候又会产生一个问题,这个时候GateWay的转发的后端路径也会带上这个后缀,但是后端的路径中是没有这个后缀的,所以得再重新规定一下GateWay转发后的地址拼接规则:

在这里插入图片描述

比如说上面这个过滤器,就表示GateWay见到地址有/renren后,又自动将其变成/,这个时候就不用担心后端的请求路径带上/renren了.

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐