/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cn.exlive.exbooter.configure;
import com.netflix.zuul.context.RequestContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.keyvalue.DefaultKeyValue;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.netflix.zuul.filters.Route;
import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
import java.net.URI;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.stream.Collectors;
/**
*
*
* Created by zhenqin.
* User: zhenqin
* Date: 2022/4/25
* Time: 下午7:12
*
*
*
* @author zhenqin
*/
@Slf4j
public class ApiRouteLocator extends SimpleRouteLocator {
/**
* zull 配置
*/
final ZuulProperties properties;
/**
* 随机策略
*/
final Random r = new Random();
public ApiRouteLocator(String servletPath, ZuulProperties properties) {
super(servletPath, properties);
this.properties = properties;
}
@Override
protected Route getRoute(ZuulProperties.ZuulRoute route, String path) {
if (route == null) {
return null;
}
RequestContext ctx = RequestContext.getCurrentContext();
final String referer = ctx.getRequest().getHeader("Referer");
final Map> queryParams = Optional.ofNullable(ctx.getRequestQueryParams()).orElse(new HashMap<>());
String clusterId = queryParams.get("clusterId") == null ? null : StringUtils.join(queryParams.get("clusterId"), ",");
if (StringUtils.isBlank(clusterId) && StringUtils.isNotBlank(referer)) {
// 如果 URL 中没有,从 Referer 中获取
final String query = URI.create(referer).getQuery();
final Map kv = Arrays.stream(query.split("&")).filter(StringUtils::isNotBlank).map(it -> {
final String[] split = it.split("=");
return split.length > 1 ? new DefaultKeyValue(split[0], split[1]) : new DefaultKeyValue(split[0], "");
}).collect(Collectors.toMap(e -> (String)e.getKey(), e -> (String)e.getValue()));
clusterId = kv.get("clusterId");
}
log.info("clusterId: {} and referer: {}", clusterId, referer);
String targetPath = path;
String prefix = this.properties.getPrefix();
if (prefix.endsWith("/")) {
prefix = prefix.substring(0, prefix.length() - 1);
}
if (path.startsWith(prefix + "/") && this.properties.isStripPrefix()) {
targetPath = path.substring(prefix.length());
}
if (route.isStripPrefix()) {
int index = route.getPath().indexOf("*") - 1;
if (index > 0) {
String routePrefix = route.getPath().substring(0, index);
targetPath = targetPath.replaceFirst(routePrefix, "");
prefix = prefix + routePrefix;
}
}
Boolean retryable = this.properties.getRetryable();
if (route.getRetryable() != null) {
retryable = route.getRetryable();
}
final HashMap globalVariables = new HashMap<>();
// cluster: 1 path: /damp/aaa/bbb match to: http://localhost:8083/damp
log.info("cluster: {} path: {} match to: {}", clusterId, path, route.getLocation());
// 如果包含逗号,说明有多个地址,需要负载均衡
if (route.getLocation().contains(",")) {
final String[] segs = route.getLocation().split(",");
// 随机策略
String loc = segs[r.nextInt(segs.length)];
// 替换路由地址
// loc = PlaceholderUtils.replacePlaceholders(loc, globalVariables, Constants.REGEX_VARIABLE);
// log.info("loc->> " + loc);
return new Route(route.getId(),
targetPath,
loc,
prefix,
retryable,
route.isCustomSensitiveHeaders() ? route.getSensitiveHeaders() : null,
route.isStripPrefix());
}
// 替换路由地址
// String loc = PlaceholderUtils.replacePlaceholders(route.getLocation(), globalVariables, Constants.REGEX_VARIABLE);
return new Route(route.getId(),
targetPath,
route.getLocation(),
prefix,
retryable,
route.isCustomSensitiveHeaders() ? route.getSensitiveHeaders() : null,
route.isStripPrefix());
}
}