前后端分离的项目肯定要使用网关,目前最流行的网关是GateWay,但部署这个网关的时候,跨域是个令人捉摸不透的问题.
可以看到上面这张图,如果出现这些信息,多半是跨域问题没解决了.
跨域问题出现的情况有很多:
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官方,看看你对应的版本的解法是怎么样的.
如果还是不行,肯定是要仔细检查,看看你是否那地方出了问题,推荐检查这些地方:
其次,最后,GateWay网关我们转发路径的时候,一般都是用lb://服务名去转发路径的,但是有时候这样子会失效,具体可能的原因是你的服务要依赖spring-cloud-starter-loadbanner,和open-feign的依赖.如果还是不行,目前没有发现解决办法,大概率是版本的问题,所以可以直接用地址转发.
小技巧: 整合人人的后端项目的时候,因为它的controller路径是有些乱的,但是我们在做GateWay网关转发的时候-Path不能直接写/**,所以我们可以在前端的访问路径中加上一个固定后缀就可以了,然后让其来匹配这个后缀,但这个时候又会产生一个问题,这个时候GateWay的转发的后端路径也会带上这个后缀,但是后端的路径中是没有这个后缀的,所以得再重新规定一下GateWay转发后的地址拼接规则:
比如说上面这个过滤器,就表示GateWay见到地址有/renren后,又自动将其变成/,这个时候就不用担心后端的请求路径带上/renren了.