SAP CAP篇十二:AppRouter 深入研究

news/2024/11/21 1:28:44/

本文目录

  • 本系列文章
  • 理解现有程序
    • `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


http://www.ppmy.cn/news/999864.html

相关文章

Arduino驱动MG-811二氧化碳传感器(气体传感器篇)

目录 1、传感器特性 2、硬件原理图 3、控制器和传感器连线图 4、驱动程序 二氧化碳是一种无色无味的气体,它是大气重要组成成分之一,CO2的过度排放、含量过高会产生温室效应等多种影响,还会危害人类和动植物的健康。 工业级MG-811 CO2探头,对CO2极为敏感,同时还能排除…

SSM(Vue3+ElementPlus+Axios+SSM前后端分离)【二】

文章目录 SSM--基础环境搭建【二】项目介绍项目功能/界面● SSM 整合项目界面 项目全局配置web.xmlSpringMVC 配置 SSM–基础环境搭建【二】 项目介绍 项目功能/界面 ● SSM 整合项目界面 项目全局配置web.xml 配置furns_ssm\src\main\webapp\WEB-INF\web.xml , 和项目全局…

docker部署jenkins且jenkins中使用docker去部署项目

docker部署jenkins且jenkins中使用docker去部署项目 1、确定版本 2.346.1是最后一个支持jdk8的 2、编写docker-compose.yml并执行 在这个目录中新增data文件夹,注意data是用来跟docker中的文件进行映射的 docker-compose.yml version: "3.1" service…

STM32F1基于标准库ST7735 1.8‘‘LCD显示DHT11数据

STM32基于标准库ST7735 1.8‘’LCD显示DHT11数据 📍HAL库驱动可以参考:《STM32基于HAL工程读取DHT11数据》🌼显示效果: 🌻ST7735 128x160 1.8’LCD屏幕 📌屏幕资料和相关驱动可以参考《1.8寸TFT LCD128…

ELK 企业级日志分析系统(ElasticSearch、Logstash 和 Kiabana 详解)

目录 一.ELK简介 1.1ELK的概述 1.2ELK的组成 1.2.1 ElasticSearch 1.2.2 Logstash 1.2.3 Kibana 1.2.4 小总结 1.3可以添加其他组件 1.4filebeat 结合 logstash 带来好处 1.5日志处理的步骤 二.Elasticsearch 2.1Elasticsearch概述 2.2Elasticsearch核心概念 2.2.1接近…

使用Python动画粒子的薛定谔波函数(ψ)(完整代码)

使用Python动画粒子的薛定谔波函数&#xff08;ψ&#xff09;&#xff08;完整代码&#xff09; 使用曲柄-尼科尔森方法求解盒子中的粒子 Kowshik chilamkurthy 以后 发表于 书技术 4 分钟阅读 2月 2021&#xff0c; <> 1.4K 5 左图&#xff1a;来源&#xff0c;右图…

JSON格式Python,Java,PHP等封装根据商品ID获取快手商品详情数据方法

快手商城是一个网上购物平台&#xff0c;售卖各类商品&#xff0c;包括服装、鞋类、家居用品、美妆产品、电子产品等。要获取拼多多商品详情数据&#xff0c;您可以通过开放平台的接口或者直接访问快手商城的网页来获取商品详情信息。以下是两种常用方法的介绍&#xff1a; 1.…

第七章 图论

第七章 图论 一、数据结构定义 图的邻接矩阵存储法#define MaxVertexNum 100 // 节点数目的最大值// 无边权&#xff0c;只用0或1表示边是否存在 bool graph[MaxVertexNum][MaxVertexNum];// 有边权 int graph[MaxVertexNum][MaxVertexNum];图的邻接表存储法 把所有节点存储为…