gateway可以實現(xiàn)支持跨域功能,但如果下游也支持跨域,會出現(xiàn)跨域沖突。
如何解決該問題,gateway對外輸出相關(guān)跨域的httpheader,只要對重復(fù)的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")) {
//如果發(fā)現(xiàn)是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為只讀,需要通過構(gòu)造響應(yīng)ServerHttpResponseDecorator 來解決只讀的問題。