rewrite插件可以帮我们重置请求的URL,这样对外可以屏蔽实际的请求地址。我们来解析一下如何使用
一、环境搭建
- soul-admin
开启 rewrite 插件:系统管理 --> 插件管理
- soul-bootstrap
soul-bootstrap/pom.xml
网关中 rewrite 依赖默认是没有的需要手动添加
<dependency>
<groupId>org.dromara</groupId>
<artifactId>soul-spring-boot-starter-plugin-rewrite</artifactId>
<version>${project.version}</version>
</dependency>
- 开启服务
soul-admin
soul-bootstrap
soul-examples-http
二、配置选择器和选择器规则
- devide 插件
我这里通过devide插件代理http请求,所以开启的devide插件,并且soul-examples-http服务开启后,数据会自动同步
无需手动添加,如果需要自定义可以自由修改
- rewrite 插件
选择器和选择器规则需要手动配置
rewriteURL 配置的是接口需要转发的实际地址
三、测试
查看网关测的日志打印,请求已经被rewrite插件成功转发
http://127.0.0.1:9195/http/test/order/findById?id=5 ----> http://10.7.254.31:8188/order/findById?id=5
➜ ~ curl -X GET \
'http://127.0.0.1:9195/http/test/order/findById?id=5' \
-H 'cache-control: no-cache' \
-H 'postman-token: 3877184f-0398-180a-12f9-8930ecfa24bf' \
-H 'test: test'
{"id":"5","name":"hello world findById"}% ➜ ~
2021-02-03 18:18:54.315 INFO 39475 --- [-work-threads-1] o.d.soul.plugin.base.AbstractSoulPlugin : rewrite selector success match , selector name :rewrite-test
2021-02-03 18:18:54.316 INFO 39475 --- [-work-threads-1] o.d.soul.plugin.base.AbstractSoulPlugin : rewrite rule success match , rule name :rewrite-rule
2021-02-03 18:18:54.318 INFO 39475 --- [-work-threads-1] o.d.soul.plugin.base.AbstractSoulPlugin : divide selector success match , selector name :/http
2021-02-03 18:18:54.318 INFO 39475 --- [-work-threads-1] o.d.soul.plugin.base.AbstractSoulPlugin : divide rule success match , rule name :/http/test/**
2021-02-03 18:18:54.327 INFO 39475 --- [-work-threads-1] o.d.s.plugin.httpclient.WebClientPlugin : The request urlPath is http://10.7.254.31:8188/order/findById?id=5, retryTimes is 0
2021-02-03 18:18:54.498 WARN 39475 --- [-work-threads-1] io.netty.bootstrap.Bootstrap : Unknown channel option 'SO_TIMEOUT' for channel '[id: 0x704e5387]'
四、解析rewrite源码
1、soul-bootstrap 加入了依赖 soul-spring-boot-starter-plugin-rewrite
org.dromara.soul.springboot.starter.plugin.rewrite.RewritePluginConfiguration
soul-bootstrap 启动后自动加载 RewritePluginConfiguration 配置类
向容器中注入RewritePlugin
@Configuration
public class RewritePluginConfiguration {
/**
* Rewrite plugin.
* @return the soul plugin
*/
@Bean
public SoulPlugin rewritePlugin() {
return new RewritePlugin();
}
}
2、RewritePlugin
模块:soul-plugin-rewrite
org.dromara.soul.plugin.rewrite.RewritePlugin
RewritePlugin —> doExecute 方法会设置 ServerWebExchange 属性 exchange.getAttributes().put(Constants.REWRITE_URI, rewriteHandle.getRewriteURI());
这就是admin后台设置的rewriteURL
这里只看到了设置rewriteURL,并没有做转发地址的替换
@Slf4j
public class RewritePlugin extends AbstractSoulPlugin {
@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.getAttributes().put(Constants.REWRITE_URI, rewriteHandle.getRewriteURI());
return chain.execute(exchange);
}
......
}
3、DividePlugin
模块:soul-plugin-divide
org.dromara.soul.plugin.divide.DividePlugin
请求来到了devide插件
DividePlugin—> doExecute—>buildRealURL 方法,做了rewriteURI地址的拼接
到此就看到了rewrite插件的处理过程
@Slf4j
public class DividePlugin extends AbstractSoulPlugin {
@Override
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 DivideRuleHandle ruleHandle = GsonUtils.getInstance().fromJson(rule.getHandle(), DivideRuleHandle.class);
final List<DivideUpstream> upstreamList = UpstreamCacheManager.getInstance().findUpstreamListBySelectorId(selector.getId());
......
String realURL = buildRealURL(domain, soulContext, exchange);
exchange.getAttributes().put(Constants.HTTP_URL, realURL);
// set the http timeout
exchange.getAttributes().put(Constants.HTTP_TIME_OUT, ruleHandle.getTimeout());
exchange.getAttributes().put(Constants.HTTP_RETRY, ruleHandle.getRetry());
return chain.execute(exchange);
}
......
private String buildRealURL(final String domain, final SoulContext soulContext, final ServerWebExchange exchange) {
String path = domain;
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;
}
}
4、debug过程