超越源码阅读之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,何乐而不为呢

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

相关推荐
卓码软件测评3 小时前
第三方软件测试机构【性能测试工具用LoadRunner还是JMeter?】
java·功能测试·测试工具·jmeter·性能优化
Lionel_SSL6 小时前
《深入理解Java虚拟机》第三章读书笔记:垃圾回收机制与内存管理
java·开发语言·jvm
记得开心一点嘛6 小时前
手搓Springboot
java·spring boot·spring
老华带你飞7 小时前
租房平台|租房管理平台小程序系统|基于java的租房系统 设计与实现(源码+数据库+文档)
java·数据库·小程序·vue·论文·毕设·租房系统管理平台
独行soc7 小时前
2025年渗透测试面试题总结-66(题目+回答)
java·网络·python·安全·web安全·adb·渗透测试
脑子慢且灵7 小时前
[JavaWeb]模拟一个简易的Tomcat服务(Servlet注解)
java·后端·servlet·tomcat·intellij-idea·web
华仔啊8 小时前
SpringBoot 中 6 种数据脱敏方案,第 5 种太强了,支持深度递归!
java·后端
异常驯兽师9 小时前
Spring 中处理 HTTP 请求参数注解全解析
java·spring·http
连合机器人10 小时前
晨曦中的守望者:当科技为景区赋予温度
java·前端·科技
AD钙奶-lalala10 小时前
idea新建的项目new 没有java class选项
java·ide·intellij-idea