Param-Mapping插件源码分析
· One min read
开始前,可以参考 这篇文章 运行shenyu网关
正文
先看一下这个插件的结构,如下图。

猜测:handler是用来做数据同步的;strategy中文意思是策略,可能是对各种请求体做了适配,应该是这个插件的重点;ParamMappingPlugin 应该是 ShenyuPlugin 的实现。
首先,看一下 ParamMappingPlugin ,里面主要是对 doExecute 方法的重写。
public Mono<Void> doExecute(final ServerWebExchange exchange, final ShenyuPluginChain chain, final SelectorData selector, final RuleData rule) {
... // paramMappingHandle判断是否为空
// 根据首部行中的contentType确定请求体类型
HttpHeaders headers = exchange.getRequest().getHeaders();
MediaType contentType = headers.getContentType();
// *
return match(contentType).apply(exchange, chain, paramMappingHandle);
}
-
match方法是根据contentType返回对应的
Operatorprivate Operator match(final MediaType mediaType) {if (MediaType.APPLICATION_JSON.isCompatibleWith(mediaType)) {return operatorMap.get(MediaType.APPLICATION_JSON.toString());} else if (MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(mediaType)) {return operatorMap.get(MediaType.APPLICATION_FORM_URLENCODED.toString());} else {return operatorMap.get(Constants.DEFAULT);}}从match方法的代码可以看出,目前有
DefaultOperator、FormDataOperator、JsonOperator三种,支持x-www-form-urlencoded和json两种格式的请求体。
那 么我们就来看一下上面三种Operator究竟是怎么样的吧。
一、DefaultOperator
虚晃一枪,它的apply方法只是继续执行插件链,并没有实质功能。当请求体没有匹配到Operator时,就会通过 DefaultOperator 跳过。
二、FormDataOperator
这个类是用来处理 x-www-form-urlencoded 格式的请求体的。
主要是看apply方法,但是这个apply方法长得有点奇怪。
public Mono<Void> apply(final ServerWebExchange exchange, final ShenyuPluginChain shenyuPluginChain, final ParamMappingHandle paramMappingHandle) {
return exchange.getFormData()
.switchIfEmpty(Mono.defer(() -> Mono.just(new LinkedMultiValueMap<>())))
.flatMap(multiValueMap -> {
...
});
}
省略号中的代码是对请求体的处理,如下。
// 判空
if (Objects.isNull(multiValueMap) || multiValueMap.isEmpty()) {
return shenyuPluginChain.execute(exchange);
}
// 将form-data转化成json
String original = GsonUtils.getInstance().toJson(multiValueMap);
LOG.info("get from data success data:{}", original);
// *修改请求体*
String modify = operation(original, paramMappingHandle);
if (StringUtils.isEmpty(modify)) {
return shenyuPluginChain.execute(exchange);
}
...
// 将修改后的json,转换成LinkedMultiValueMap。注意一下这一行,后面会提到!
LinkedMultiValueMap<String, String> modifyMap = GsonUtils.getInstance().toLinkedMultiValueMap(modify);
...
final BodyInserter bodyInserter = BodyInserters.fromValue(modifyMap);
...
// 修改exchange中的请求体,然后继续执行插件链
return bodyInserter.insert(cachedBodyOutputMessage, new BodyInserterContext())
.then(Mono.defer(() -> shenyuPluginChain.execute(exchange.mutate()
.request(new ModifyServerHttpRequestDecorator(httpHeaders, exchange.getRequest(), cachedBodyOutputMessage))
.build())
)).onErrorResume((Function<Throwable, Mono<Void>>) throwable -> release(cachedBodyOutputMessage, throwable));
PS: 省略的部分是设置请求头等操作。