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

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

我们大家绝大数人碰到源码一开始都是比较无从下手的,不知道从哪开始阅读、阅读了有什么用。我认为有一种方法,可以解决上面的问题,让我们既知道了从哪开始阅读源码,又能够从阅读源码中获得收获。
那就是通过阅读某一次开源commit 、某一次ISSUE的提出,从这个入口出发,去探索源码。
通过上面的方法,我们可以从堆砌的源码中脱离开来,去阅读其中让我们更有兴趣的部分,都说兴趣是最好的老师,兴趣老师会引导我们走向正确的道路,让我们获取我们需要的收获,最后甚至还会送给你一朵小红花当作奖励嘻嘻🤭。

前瞻

那就让我们从这次开源提交开始:ISSUE链接

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

探索

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

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

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

java 复制代码
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,何乐而不为呢

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

相关推荐
lkbhua莱克瓦2418 分钟前
Java基础——集合进阶用到的数据结构知识点1
java·数据结构·笔记·github
音符犹如代码1 小时前
Java并发List实战:CopyOnWriteArrayList原理与ArrayList常见面试题
java·开发语言·面试·list
代码or搬砖1 小时前
Docker 部署 Java 项目实践
java·docker·容器
又是忙碌的一天1 小时前
抽象类和接口
java·开发语言
August_._2 小时前
【MySQL】SQL语法详细总结
java·数据库·后端·sql·mysql·oracle
Dxxyyyy2 小时前
零基础学JAVA--Day26(枚举类)
java·开发语言
黑屋里的马2 小时前
java的设计模式之桥接模式(Bridge)
java·算法·桥接模式
升鲜宝供应链及收银系统源代码服务2 小时前
升鲜宝生鲜配送供应链管理系统---PMS--商品品牌多语言存储与 Redis 缓存同步实现
java·开发语言·数据库·redis·缓存·开源·供应链系统
练习时长一年2 小时前
Spring AoP的切点匹配
java·开发语言
27669582922 小时前
朴朴超市小程序分析
java·python·小程序·node·sign·朴朴超市·sign-v2