gateway可以实现支持跨域功能,但如果下游也支持跨域,会出现跨域冲突。
如何解决该问题,gateway对外输出相关跨域的httpheader,只要对重复的header去掉即可。
/**
* @author starmark
* @date 2020/5/11 下午9:29
*/
@Slf4j
public class GatewayCorsWebFilter implements WebFilter {
@Autowired
private IRouteService routeService;
private final CorsProcessor processor;
private static List<String> configHeaderNames = new ArrayList<>();
static{
configHeaderNames.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS);
configHeaderNames.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS);
configHeaderNames.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS);
configHeaderNames.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN);
configHeaderNames.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS);
}
public GatewayCorsWebFilter() {
this.processor = new DefaultCorsProcessor();
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String url = request.getPath().value();
if (url.contains("webjars") || url.contains("swagger-resources") || url.contains("/v2/api-docs") || url.contains("doc.html") || url.contains("swagger-ui.html") ||
url.contains(".css") || url.contains(".ico") || url.contains(".js") || url.contains(".png") || url.contains(".jpg")) {
//如果发现是css或者js文件,直接放行
return chain.filter(exchange);
}
String projectCode = RequestHelper.getRequestProjectCode(request);
Assert.hasText(projectCode, "工程编码不存在");
CorsConfiguration corsConfiguration = routeService.getGatewayProjectCorsConfiguration(projectCode);
boolean isValid = this.processor.process(corsConfiguration, exchange);
if (!isValid || CorsUtils.isPreFlightRequest(request)) {
return Mono.empty();
}
//解决跨域冲突的问题
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(exchange.getResponse()) {
@Override
public HttpHeaders getHeaders() {
HttpHeaders httpHeaders= HttpHeaders.writableHttpHeaders(getDelegate().getHeaders());
dedupe(httpHeaders);
return httpHeaders;
}
void dedupe(HttpHeaders headers) {
if (headers == null) {
return;
}
for (String name : configHeaderNames) {
dedupe(headers, name.trim());
}
}
private void dedupe(HttpHeaders headers, String name) {
List<String> values = headers.get(name);
if (values == null || values.size() <= 1) {
return;
}
headers.set(name, values.get(values.size() - 1));
}
};
return chain.filter(exchange.mutate().response(decoratedResponse).build());
}
}
上述是我跨域功能的代码,支持跨域功能及解决跨域冲突功能的问题。
上面有一个梗, exchange.getResponse().getHeaders()的header为只读,需要通过构造响应ServerHttpResponseDecorator 来解决只读的问题。
网友评论