超越源码阅读之shenyu网关-响应参数插件

超越源码阅读之shenyu网关-响应参数插件

我们大家绝大数人碰到源码一开始都是比较无从下手的,不知道从哪开始阅读、阅读了有什么用。我认为有一种方法,可以解决上面的问题,让我们既知道了从哪开始阅读源码,又能够从阅读源码中获得收获。

那就是通过阅读某一次开源commit、某一次ISSUE的提出,从这个入口出发,去探索源码。

通过上面的方法,我们可以从堆砌的源码中脱离开来,去阅读其中让我们更有兴趣的部分,都说兴趣是最好的老师,兴趣老师会引导我们走向正确的道路,让我们获取我们需要的收获,最后甚至还会送给你一朵小红花当作奖励嘻嘻🤭。

前瞻

那就让我们从这次开源提交开始:ISSUE链接
在这里插入图片描述

从这次ISSUE可以知道,本次开源commit是增加一个接口响应码的插件

探索

通过对所有提交的查看,把核心类锁定在ModifyResponsePlugin,以下就核心类开始对本次commit进行探索。
在这里插入图片描述

我们可以看到核心方法doExecute把shenyu对响应插件的自定义规则Rule,传入到Spring框架自带的ServerWebExchange进行修改,入参new ModifyResponseDecorator(exchange, ruleHandle)).build()也就是提交者对响应参数的所作出的修改。
在这里插入图片描述

ModifyResponseDecorator类如下,buildModifiedResponse方法就是关键,修改的代码没什么好说的可以自己看看。

static class ModifyResponseDecorator extends ServerHttpResponseDecorator {

        private final ServerWebExchange exchange;

        private final ModifyResponseRuleHandle ruleHandle;

        ModifyResponseDecorator(final ServerWebExchange exchange,
                                final ModifyResponseRuleHandle ruleHandle) {
            super(exchange.getResponse());
            this.exchange = exchange;
            this.ruleHandle = ruleHandle;
        }

        @Override
        @NonNull
        public Mono<Void> writeWith(@NonNull final Publisher<? extends DataBuffer> body) {
            final Mono<DataBuffer> dataBufferMono = DataBufferUtils.join(body);
            buildModifiedResponse(body);
            return dataBufferMono.flatMap(dataBuffer -> {
                byte[] bytes = new byte[dataBuffer.readableByteCount()];
                dataBuffer.read(bytes);
                return WebFluxResultUtils.result(this.exchange, modifyBody(bytes));
            });
        }

        private void buildModifiedResponse(final Publisher<? extends DataBuffer> body) {
            HttpHeaders httpHeaders = new HttpHeaders();
            // add origin headers
            httpHeaders.addAll(this.getHeaders());

            // add new headers
            if (MapUtils.isNotEmpty(this.ruleHandle.getAddHeaders())) {
                Map<String, String> addHeaderMap = this.ruleHandle.getAddHeaders();
                addHeaderMap.forEach(httpHeaders::add);
            }

            // set new headers
            if (MapUtils.isNotEmpty(this.ruleHandle.getSetHeaders())) {
                Map<String, String> setHeaderMap = this.ruleHandle.getSetHeaders();
                setHeaderMap.forEach(httpHeaders::set);
            }

            // replace headers
            if (MapUtils.isNotEmpty(this.ruleHandle.getReplaceHeaderKeys())) {
                Map<String, String> replaceHeaderMap = this.ruleHandle.getReplaceHeaderKeys();
                replaceHeaderMap.forEach((key, value) -> httpHeaders.replace(key, Collections.singletonList(value)));
            }

            // remove headers
            if (CollectionUtils.isNotEmpty(this.ruleHandle.getRemoveHeaderKeys())) {
                Set<String> removeHeaderList = this.ruleHandle.getRemoveHeaderKeys();
                removeHeaderList.forEach(httpHeaders::remove);
            }

            // reset http status
            if (this.ruleHandle.getStatusCode() > 0) {
                this.setStatusCode(HttpStatus.valueOf(this.ruleHandle.getStatusCode()));
            }

            // reset http headers
            this.getDelegate().getHeaders().clear();
            this.getDelegate().getHeaders().putAll(httpHeaders);
        }

        private byte[] modifyBody(final byte[] responseBody) {
            try {
                String bodyStr = modifyBody(new String(responseBody, StandardCharsets.UTF_8));
                LOG.info("the body string {}", bodyStr);
                return bodyStr.getBytes(StandardCharsets.UTF_8);
            } catch (Exception e) {
                LOG.error("modify response error", e);
                throw new ShenyuException(String.format("response modify failure. %s", e.getLocalizedMessage()));
            }
        }

        private String modifyBody(final String jsonValue) {
            DocumentContext context = JsonPath.parse(jsonValue);
            if (CollectionUtils.isNotEmpty(this.ruleHandle.getAddBodyKeys())) {
                this.ruleHandle.getAddBodyKeys().forEach(info -> context.put(info.getPath(), info.getKey(), info.getValue()));
            }
            if (CollectionUtils.isNotEmpty(this.ruleHandle.getReplaceBodyKeys())) {
                this.ruleHandle.getReplaceBodyKeys().forEach(info -> context.renameKey(info.getPath(), info.getKey(), info.getValue()));
            }
            if (CollectionUtils.isNotEmpty(this.ruleHandle.getRemoveBodyKeys())) {
                this.ruleHandle.getRemoveBodyKeys().forEach(context::delete);
            }
            return context.jsonString();
        }
    }

总结

仔细一看buildModifiedResponse方法的入参body的没有使用到,且该方法的命名也有不妥,modifyResponseHeadersAndStatus这个命名更易理解也更符合代码修改。赶紧提一次commit哈哈:commit链接
在这里插入图片描述

又收获了一次开源提交!!!

能否感受通过commit、ISSUE这种方式来阅读源码的乐趣呢,学习了知识、获得了开源commit,何乐而不为呢

对作者感兴趣的话,不妨关注、点赞、收藏支持一下嘞!😘

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值