当前位置: 首页 > news >正文

SAP CAP篇十二:AppRouter 深入研究

本文目录

  • 本系列文章
  • 理解现有程序
    • `app`文件夹中的`package.json`
    • 理解`approuter.js`
  • 修改现有程序
    • 修改`package.json`
    • 新建`index.js`
    • 在Approuter中显示额外的逻辑
  • 添加一些额外的Logger
  • 对应代码及branch

本系列文章

SAP CAP篇一: 快速创建一个Service,基于Java的实现
SAP CAP篇二:为Service加上数据库支持
SAP CAP篇三:定义Model
SAP CAP篇四:为CAP添加Fiori Elements程序(1)
SAP CAP篇五:为CAP添加Fiori Elements程序(2)
SAP CAP篇六:为CAP添加Fiori Elements程序(3)
SAP CAP篇七:为CAP添加Fiori Launchpad入口 (Sandbox环境)
SAP CAP篇八:为CAP添加App Router并支持Fiori Launchpad (Sandbox环境)
SAP CAP篇九:升级为SAP CDS 7.0, CAP Java 2以及Spring Boot 3
SAP CAP篇十:理解Fiori UI的Annoation定义
SAP CAP篇十一:支持Media Object:图片、附件等
SAP CAP篇十二:AppRouter 深入研究

理解现有程序

本篇基于上一篇 SAP CAP篇十一:支持Media Object:图片、附件等 代码基础。

app文件夹中的package.json

打开app文件夹中的package.json,可以发现start命令定义如下:

"scripts": {"start": "node node_modules/@sap/approuter/approuter.js"
}

理解approuter.js

看看上述start命令的approuter.js,其中,关键的部分是文件末尾的启动AppRouter部分。

if (require.main === module) {let ar = new Approuter();ar.start();
}

修改现有程序

理解了现有程序之后,可以对现有程序进行修改。

修改package.json

本步骤的修改是在app文件夹下。

修改package.json文件中的’scripts’部分:

"scripts": {"start": "node index.js"
}

新建index.js

由上述script所示,这里的start命令将执行index.js

该新建的index.js文件如下:

const approuter = require('@sap/approuter');
const ar = approuter();ar.start();

其实,上段代码其实就是Approuter.js的核心启动代码:

这时候,启动Service跟Approuter,所有功能都正常运行。换言之,上述代码修改是功能无损的修改,但是它提供了额外的可能。

在Approuter中显示额外的逻辑

如果仔细研读approuter.js的源码,它其实是node.js的程序。而其中的start方法是其中的关键:

Approuter.prototype.start = function (options, callback) {let self = this;if (dynamicRoutingUtils.isDynamicRouting()) {self.first.use(dynamicRoutingUtils.initialize(self));if (options) {delete options.port;options.getRouterConfig = dynamicRoutingUtils.getRouterConfig;} else {options = {'getRouterConfig': dynamicRoutingUtils.getRouterConfig};}}if (options) {validators.validateApprouterStartOptions(options);options = _.cloneDeep(options);} else {options = {};}callback = optionalCallback(callback);if (this.cmdParser) {this.cmdParser.parse(process.argv);options = _.defaults(options, this.cmdParser);}addImplicitExtension(this, options);let logger = loggerUtil.getLogger('/approuter');logger.info('Application router version %s', require('./package.json').version);let app = bootstrap(options);app.logger = logger;app.approuter = this;this._app = app;loggerUtil.getAuditLogger(function(err, auditLogger){if (err) {throw err;}app.auditLogger = auditLogger;serverLib.start(app, function (err, server) {self._server = server;callback(err);});});
};

继续研读下去,其中最关键的serverLib.start(...)的逻辑实现在一个server.js的文件中,而server的start方法:

exports.start = function (app, callback) {let routerConfig = app.get('mainRouterConfig');let server;if (routerConfig.http2Support){server = http2.createServer(app);} else if (routerConfig.httpsOptions) {server = https.createServer(routerConfig.httpsOptions, app);} else {server = http.createServer(app);}if (routerConfig.incomingConnectionTimeout !== undefined) {server.timeout = routerConfig.incomingConnectionTimeout;}server.keepAliveTimeout = routerConfig.serverKeepAlive || 0;let wsServer = new WsProxy(app);wsServer.listen(server);server.on('error', callback);server.listen(routerConfig.serverPort, function () {app.logger.info('Application router is listening on port: ' +server.address().port);callback(undefined, new Server(server, wsServer));});
};

而引用到的lib在文件头部有定义:

const http = require('http');
const https = require('https');
const http2 = require('http2');
const WsProxy = require('./websockets/WsProxy');
const util = require('util');

至此,AppRouter的逻辑很清楚了,就是一个基于nodejs的server。所以,通过其可以实现一定额外的逻辑,譬如proxy之类。

添加一些额外的Logger

虽然可以通过Approuter实现类似proxy的逻辑,但是这不是本篇的重点。接下来,通过AppRouter来实现额外的Log写入逻辑,作为测试。

const approuter = require('@sap/approuter');
const { Console } = require("console");// get fs module for creating write streams
const fs = require("fs");ar.beforeRequestHandler.use('/api', async (req, res, next) => {const myLogger = new Console({stdout: fs.createWriteStream("normalStdout.txt"),stderr: fs.createWriteStream("errStdErr.txt"),});const { rawHeaders, method, originalUrl, url } = req;let body = [];let errorMessage = null;// saving to normalStdout.txt filemyLogger.log(`originalUrl = ${originalUrl}`);myLogger.log(`method = ${method}`);myLogger.log(JSON.stringify(rawHeaders));//    if (method === 'POST' || method === 'PUT') {
//        myLogger.log(`========================================`);
//        myLogger.log(req);//        for await (const chunk of req) {
//            myLogger.log(`+++ 111 ++++++++++++++++++++++++++++++`);
//            myLogger.log(`+++ ${Date.now()} for each data`);
//            myLogger.log(`Log Callback of 'on': ${chunk}`);
//            body.push(chunk);
//        }
//        myLogger.log(`+++ 222 ++++++++++++++++++++++++++++++`);
//        myLogger.log(`+++ ${Date.now()} of all`);
//        body = Buffer.concat(body).toString();
//        myLogger.log(`Log Callback of 'end': ${body}`);//        myLogger.log(`========================================`);
//        myLogger.log(req);
//    }myLogger.log(`+++ 000 ++++++++++++++++++++++++++++++`);myLogger.log(`+++ ${Date.now()} before next()`);next();
});

运行后,所有的对/api的情节都会被写入额外的normalStdout.txt

其中,被注释的代码部分会打印完整requestbody部分,但是作为副作用,request这个stream已经被close了,next()再发送到后续的处理就会失败,所以这里的代码仅作为参考用途。

对应代码及branch

与本文配套的代码参见这里。

本篇对应的branch是8_approuter

相关文章:

SAP CAP篇十二:AppRouter 深入研究

本文目录 本系列文章理解现有程序app文件夹中的package.json理解approuter.js 修改现有程序修改package.json新建index.js在Approuter中显示额外的逻辑 添加一些额外的Logger对应代码及branch 本系列文章 SAP CAP篇一: 快速创建一个Service,基于Java的实现 SAP CAP…...

HDFS中数据迁移的使用场景和考量因素

HDFS中数据迁移的使用场景和考量因素 数据迁移使用场景数据迁移要素考量HDFS分布式拷贝工具-DistCpdistcp的优势性能命令 数据迁移使用场景 冷热集群数据同步、分类存储集群数据整体搬迁 当公司业务迅速的发展,导致的当前的服务器数量资源出现临时紧张的时候&#…...

科普 | 以太坊坎昆升级是什么

坎昆升级是什么 坎昆,是墨西哥一个著名的旅游城市,也是 Devcon 3 大会的举办地,按照以太坊升级命名的规律,以地名命名的升级,是针对以太坊执行层的升级。 之前同样命名的还有柏林升级、伦敦升级和这次的上海升级等。…...

C# 一些知识整理

C#反射和特性 反射Reflection Type 类型 Name NameSpace Assembly GetFields() GetProperties() GetMethods() 特性Attribute Obsolete弃用 Condit…...

SpringBoot复习:(15)Spring容器的核心方法refresh是在哪里被调用的?

在SpringApplication的run方法: refreshContext代码如下: 其中调用的refresh方法代码如下: 其中调用的refresh方法代码如下: 其中调用的fresh方法代码如下: 其中调用了super.refresh();而这个super.refresh()就是…...

Android安卓实战项目(5)---完整的健身APP基于安卓(源码在文末)可用于比赛项目或者作业参考中

Android安卓实战项目(5)—完整的健身APP(源码在文末🐕🐕🐕)可用于比赛项目 一.项目运行介绍 1.大致浏览 【bilibili视频】 https://www.bilibili.com/video/BV1uX4y177iR/? (1&…...

AutoSAR系列讲解(实践篇)11.2-存储处理与Block

目录 一、NVRAM Block NVRAM Block的类型 二、Fee Block 三、Ea Block 四、总结 同通信的PDU一样,存储功能也需要一些特殊的数据结构来存放和管理我们的NV数据(NV data) 一、NVRAM Block NVRAM Block的作用类似于IPDU,但它们两仅仅只是作用上相似,其功能实现是完全…...

K8s总结

K8s 是什么 Kubernetes是一个开源的,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器化的应用简单并且高效(powerful),Kubernetes提供了应用部署,规划,更新,维护的机制…...

3.playbook剧本二

文章目录 playbook二Roles模块roles模式安装LNMP创建nginxfiles目录handlers目录tasks目录templates目录vars目录 创建mysqltasks目录 创建phpfiles目录handlers目录tasks目录templates目录vars目录 创建LNMP剧本文件 playbook二 Roles模块 角色的作用:把playbook…...

【MySQL】视图与用户管理

【MySQL】视图 视图视图概念使用基表与视图的相互影响 用户管理新增用户删除修改密码 用户权限授予权限回收权限 视图 视图概念 视图就是一张虚拟表,其内容由查询定义。与真实的表一样,视图包含一系列带有名称的列和行数据。视图的数据变化影响到基表&…...

LINUX系统监控工具ATOP的使用

最近在排查嵌入式系统的问题,需要监控各种系统资源的消耗。 ATOP不错,可以实时看,也可以保存成日志,分析历史情况。 直接使用: atop 想写入文件就是: sudo atop -a -w /home/guo/atoplog2.log 2 2的意…...

[回馈]ASP.NET Core MVC开发实战之商城系统(五)

经过一段时间的准备,新的一期【ASP.NET Core MVC开发实战之商城系统】已经开始,在之前的文章中,讲解了商城系统的整体功能设计,页面布局设计,环境搭建,系统配置,及首页【商品类型,ba…...

iPhone 8透明屏的透明度高吗?

iPhone 8是苹果公司于2017年推出的一款智能手机,它采用了全新的设计和技术,其中一个亮点就是透明屏。 透明屏是指屏幕具有透明度,可以透过屏幕看到背后的物体。 iPhone 8的透明屏采用了最新的OLED技术,这种技术可以实现更高的对比…...

Vue2 第十五节 组件间通信方式

1.组件的自定义事件 2.全局事件总线 3.消息订阅与发布 一.组件的自定义事件 1.1 绑定自定义事件 ① 自定义事件就是一种组件间通信方式,用于子组件和父组件之间传递数据 ② props来实现子组件给父组件传递数据 (1)先给父组件中绑定一个…...

maven的下载与安装

文章目录 1 官网下载地址2 设置环境变量3 设置仓库地址4 添加阿里云的中央镜像 1 官网下载地址 https://maven.apache.org/ 下载 2 设置环境变量 MAVEN_HOME PATH mvn -v验证 3 设置仓库地址 仓库地址 4 添加阿里云的中央镜像 阿里云中央镜像...

BroadcastChannel 实现浏览器tab无刷新通讯

前提须知 使用 BroadcastChannel 来实现浏览器tab通讯必须是同源的BroadcastChannel 支持多tab间通讯mdn 链接 具体使用 发送方使用 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewpor…...

98. Python基础教程:try...except...finally语句

【目录】 文章目录 1. try...except...finally语法介绍2. try...except...finally执行顺序3. 捕获特定类型的异常4. 捕获所有类型的异常5. 实操练习-打开txt文件并输出文件内容 【正文】 在今天的课程中&#xff0c;我们将学习Python中的异常处理语句try...except...finally。 …...

c语言实现简单的tcp客户端

功能&#xff1a;实现一个简单的tcp客户端&#xff0c;连接本地端口8888的tcp服务端&#xff0c;并发送一条报文。 /* * File: main.c* Author: vincent** Created on 2023年8月3日, 上午9:56*/#include <stdio.h> #include <stdlib.h> #include <string.h…...

RocketMQ详解及注意事项

RocketMQ是阿里巴巴开源的一款分布式消息中间件&#xff0c;具有高吞吐量、高可用性、可扩展性和稳定性强等特点&#xff0c;广泛应用于异步消息、应用解耦、流量削峰填谷等场景。本文将详细介绍RocketMQ的基本架构、工作流程、消息模型&#xff0c;并列出在使用RocketMQ时需要…...

选择适合的项目管理系统,了解有哪些选择和推荐

随着科技的进步和全球竞争的加剧&#xff0c;项目管理已经成为企业成功的关键要素。为了更好地组织和监控项目&#xff0c;许多企业和组织正在采用项目管理系统(PMS)。本文将探讨项目管理系统的主要组成部分以及其在实际应用中的优势。 “项目管理系统有哪些?国际上比较常见的…...

从YOLOv8到RTDETR:如何将训练后的YOLO指标无缝转换为COCO格式

1. 为什么需要YOLO到COCO格式转换 当你用YOLOv8官方代码训练RTDETR模型时&#xff0c;会发现评估结果默认输出的是YOLO格式指标。但学术界和工业界普遍采用COCO评估标准&#xff0c;这就好比在中国用人民币交易&#xff0c;到了欧洲就得换成欧元。我在去年帮某无人机公司做目标…...

GIL移除≠自动线程安全!揭秘Python 3.13+中asyncio+shared_memory+numpy.ndarray三者交汇处的5个未公开竞态漏洞

第一章&#xff1a;Python无锁GIL环境下的并发安全本质重构当Python脱离CPython解释器的全局解释器锁&#xff08;GIL&#xff09;约束——例如在PyPy的STM模式、Jython、Cython多线程扩展&#xff0c;或新兴的Rust-Python绑定&#xff08;如PyO3 async-std&#xff09;中运行…...

从apt-get到yum:Ubuntu20.04下跨平台包管理工具安装指南

从apt-get到yum&#xff1a;Ubuntu 20.04下跨平台包管理工具实战指南 在Linux生态中&#xff0c;不同发行版采用不同的包管理系统——Debian系的apt与RedHat系的yum就是典型代表。当开发者需要在Ubuntu环境下运行原本为CentOS设计的软件时&#xff0c;掌握yum的安装与配置技巧能…...

华为HMS Scan Kit Customized View Mode:打造品牌专属扫码界面的实战指南

1. 为什么选择Customized View Mode&#xff1f; 扫码功能已经成为现代App的标配&#xff0c;但很多开发者面临一个两难选择&#xff1a;要么用系统默认的扫码界面显得千篇一律&#xff0c;要么完全自己开发一套又耗时耗力。华为HMS Scan Kit的Customized View Mode正好解决了这…...

网络调试无从下手?Fiddler中文版让HTTP问题排查效率提升10倍的秘密

网络调试无从下手&#xff1f;Fiddler中文版让HTTP问题排查效率提升10倍的秘密 【免费下载链接】zh-fiddler Fiddler Web Debugger 中文版 项目地址: https://gitcode.com/gh_mirrors/zh/zh-fiddler 在当今复杂的网络环境中&#xff0c;开发者和测试工程师经常面临HTTP请…...

Java外部函数接口不是“能用就行”——从内存泄漏、线程崩溃到ABI不兼容,这9类致命缺陷正在 silently 摧毁你的微服务

第一章&#xff1a;Java外部函数接口&#xff08;JEP 454&#xff09;核心原理与演进脉络Java外部函数接口&#xff08;Foreign Function & Memory API&#xff0c;JEP 454&#xff09;标志着Java平台原生互操作能力的根本性重构。它取代了长期受限且易出错的JNI&#xff0…...

VSCode配置PyTorch开发环境:从CUDA版本检查到镜像源加速(附常见报错解决方案)

VSCode配置PyTorch开发环境&#xff1a;从CUDA版本检查到镜像源加速&#xff08;附常见报错解决方案&#xff09; 在深度学习领域&#xff0c;PyTorch凭借其动态计算图和易用性已成为研究者和开发者的首选框架。然而&#xff0c;配置PyTorch开发环境时&#xff0c;CUDA版本匹配…...

W25Q128JWSIQ 串行 NOR Flash 存储器 Winbond 全新原装 进口芯片IC

W25Q128JWSIQ 是华邦&#xff08;Winbond&#xff09;推出的一款1.8V 128Mbit 高速串行 NOR Flash 存储器&#xff0c;采用 133MHz 四线 SPI 接口和 SOIC-8 封装&#xff0c;具备超低功耗、工业级宽温工作范围和高可靠性等特性&#xff0c;是物联网设备、汽车电子、工业控制等低…...

DLSS Swapper实战手册:游戏性能调优与版本管理深度解析

DLSS Swapper实战手册&#xff1a;游戏性能调优与版本管理深度解析 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper 还在为游戏中的DLSS版本过时而烦恼吗&#xff1f;DLSS Swapper为您提供了一套完整的解决方案&#xf…...

Wireshark抓包实战:用一道CTF题彻底搞懂IP分片与UDP重组

Wireshark抓包实战&#xff1a;用一道CTF题彻底搞懂IP分片与UDP重组 在网络安全竞赛中&#xff0c;一个看似简单的UDP传输任务可能隐藏着协议层面的精妙设计。去年CyBRICS赛事中的lx100题目就完美诠释了这一点——参赛者需要从相机传输的UDP流量中提取图片&#xff0c;而真正的…...