1.运行 context-path 插件
我们在使用 soul 网关时,yml 文件里就配置了 contextPath,不过我们可以使用 context_path 插件进行重写,这也体现了 soul 网关的灵活配置
登录 soul-admin 开启 context-path 插件,选择器规则配置如下
我们使用网关 http://localhost:9195/context/http/order/findById?id=3 访问时,真正执行的 url 就是 http://192.168.1.99:8188/order/findById?id=3
接下来看看 ContextPathMappingPlugin 是怎么执行的。
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
final SoulContext soulContext = exchange.getAttribute(Constants.CONTEXT);
assert soulContext != null;
final String handle = rule.getHandle();
//获取配置的 context path
final ContextMappingHandle contextMappingHandle = GsonUtils.getInstance().fromJson(handle, ContextMappingHandle.class);
if (Objects.isNull(contextMappingHandle) || StringUtils.isBlank(contextMappingHandle.getContextPath())) {
log.error("context path mapping rule configuration is null :{}", rule);
return chain.execute(exchange);
}
//判断请求的路径是不是以我们配置的 context path 开头
if (!soulContext.getPath().startsWith(contextMappingHandle.getContextPath())) {
Object error = SoulResultWrap.error(SoulResultEnum.CONTEXT_PATH_ERROR.getCode(), SoulResultEnum.CONTEXT_PATH_ERROR.getMsg(), null);
return WebFluxResultUtils.result(exchange, error);
}
//使用 context path 获取请求的url
this.buildContextPath(soulContext, contextMappingHandle);
return chain.execute(exchange);
}
private void buildContextPath(final SoulContext context, final ContextMappingHandle handle) {
context.setContextPath(handle.getContextPath());
if (!StringUtils.isBlank(handle.getRealUrl())) {
log.info("context path mappingPlugin replaced old :{} , real:{}", context.getRealUrl(), handle.getRealUrl());
context.setRealUrl(handle.getRealUrl());
return;
}
//获取真实的 url
Optional<String> optional = Arrays.stream(context.getPath()
.split(handle.getContextPath()))
.reduce((first, last) -> last);
optional.ifPresent(context::setRealUrl);
}
2.运行 rewrite 插件,规则配置如下
这里就重写了我们的 url,真正的访问地址就被修改了。
看下 rewrite 插件的源码,这部分比较简单,就是拿到 rewrite_uri,放到 exchange 里。接着就继续执行下一个插件。
@Override
protected Mono<Void> doExecute(final ServerWebExchange exchange, final SoulPluginChain chain, final SelectorData selector, final RuleData rule) {
String handle = rule.getHandle();
final RewriteHandle rewriteHandle = GsonUtils.getInstance().fromJson(handle, RewriteHandle.class);
if (Objects.isNull(rewriteHandle) || StringUtils.isBlank(rewriteHandle.getRewriteURI())) {
log.error("uri rewrite rule can not configuration:{}", handle);
return chain.execute(exchange);
}
//放到 exchange
exchange.getAttributes().put(Constants.REWRITE_URI, rewriteHandle.getRewriteURI());
return chain.execute(exchange);
}
使用是在 DividePlugin 使用的
private String buildRealURL(final String domain, final SoulContext soulContext, final ServerWebExchange exchange) {
String path = domain;
//获取 rewrite
final String rewriteURI = (String) exchange.getAttributes().get(Constants.REWRITE_URI);
if (StringUtils.isNoneBlank(rewriteURI)) {
path = path + rewriteURI;
} else {
final String realUrl = soulContext.getRealUrl();
if (StringUtils.isNoneBlank(realUrl)) {
path = path + realUrl;
}
}
String query = exchange.getRequest().getURI().getQuery();
if (StringUtils.isNoneBlank(query)) {
return path + "?" + query;
}
return path;
}
这两部分的源码实现都比较简单。但却为我们使用 soul 网关时,多提供了一些选择。