GMTC北京站9折购票倒计时,部分日程已上线,戳此查看 了解详情
写点什么

企业应用上云的新花样:利用 Amazon API Gateway 和 AWS Lambda 实现 SAP 应用微服务化

  • 2019 年 10 月 22 日
  • 本文字数:6151 字

    阅读完需:约 20 分钟

企业应用上云的新花样:利用 Amazon API Gateway 和 AWS Lambda 实现 SAP 应用微服务化

企业应用(如 ERP、CRM、OA 和 HR 等)是企业信息系统的核心资产,支撑企业的生产、经营与管理。随着移动互联网的蓬勃发展,这些企业应用迫切需要向移动设备提供便捷、高效的访问,实现丰富的用户体验。例如,销售人员通过手机 App 管理客户信息、拜访记录和订单等;差旅途中的管理人员在平板电脑上浏览财务报表或审批公文等。此外,集团型的企业客户日益注重 IT 服务能力的输出与共享,以促进各业务板块及生态圈的协同发展。例如,构建统一的身份认证平台为所有的第三方应用提供认证与授权服务。


一般来说,企业应用通过开放 API (Application programming interfaces)的方式实现应用集成与能力共享。例如,SAP 应用(如 ERP/CRM/SRM/SCM/PLM 等)发布的是基于 OData (Open Data Protocol) 协议封装的 API,而且满足 REST 设计风格(关于 OData 协议的更多介绍,请参见 SAP 官方博客)。这些 API 为企业应用在云上的微服务化提供了机会。此外,还需要 API 管理平台对 API 进行统一的管理,包括发布与部署、安全认证、流量控制和监控告警等。Amazon API Gateway 是实现 API 管理平台的托管式服务,它提供了统一、安全、敏捷及可扩展的 API 生产与消费方式。API Gateway 可以创建 API 直接与后台的各类企业应用集成;也可以结合 AWS Lambda,实现定制化的业务逻辑与管理功能,构建轻量级、松耦合的无服务器式微服务。利用 API Gateway 和 Lambda 实现微服务的另外一个显著优势是,可以充分发挥无服务器架构中缓存和动态扩容的特性,降低前端应用对后台企业应用的访问压力,并优化用户体验。关于 API Gateway 的更多特性,请参见产品主页



我的同事 KK Ramamoorthy 在近期的一篇文章中介绍了利用 API Gateway 部署 SAP API 的方法,移动 App 和 Web 应用可以通过 API Gateway 直接访问 SAP 开放的 OData API endpoints,轻松实现 API 的调用。


根据企业对云上环境的安全分区要求及 AWS 最佳实践,SAP 应用一般是部署在 VPC 的私有子网,不允许被公网直接访问,因此,API Gateway 无法创建 API 直接调用位于私有子网的 OData API endpoints。此外, OData API 采用了安全令牌机制防范 CSRF (Cross-site request forgery) 攻击(即在调用 POST 方法之前必须先请求获得 X-CSRF-Token),这一机制也限制了 API Gateway 直接对 SAP 应用进行微服务化。针对上述两个问题,本文将介绍通过 Lambda 函数结合 API Gateway 实现安全、灵活的 SAP 应用微服务。Lambda 函数完成的工作机制如下:


  1. 作为 API Gateway 的代理,将调用请求转发到位于私有子网的 OData API endpoint;

  2. 对于 API Gateway 的 GET 方法,直接提交 GET 请求;

  3. 对于 API Gateway 的 POST 方法,先请求 CSRF 令牌,再提交 POST 请求;

  4. 实现基本的身份认证(用户名与密码)。


部署架构


  • 在 VPC 私有子网中部署 SAP 应用。其中,SAP Gateway 是 OData API 的开发和运行环境,SAP 后台应用可以是 ERP/CRM/SCM 等。本示例采用的是 S/4 HANA(内嵌了 Gateway)。启用 Gateway 内置的 “RMTSAMPLEFLIGHT” 服务。该示例服务提供了一组管理航班旅行的 OData API。在后续的示例中,将展示如何在 API Gateway 创建 API 以查询和添加旅行社信息。

  • 在 VPC 公共子网中部署 Lambda 函数 ”sapapi-proxy”,作为 API Gateway 调用后台 OData API 的代理。

  • 定义安全组 “SAP” 对 SAP S/4 HANA 进行隔离保护,即只允许来自安全组 “SAP Proxy” 的 Lambda 函数访问 OData API。

  • 必须为 VPC 中的 Lambda 函数分配网络接口即 ENI (Elastic Network Interfaces) ,因此,需要定义 AWS IAM 权限策略,授予 Lambda 函数管理 ENI 的权限。

  • 在 Amazon CloudWatch Logs 创建 Flow Logs,对 API 调用过程中的网络流量进行监控。


以下将针对 API Gateway 的配置和 Lambda 函数的实现展开详细的介绍。


API Gateway 的配置

在 API Gateway 为 OData API 服务创建对应的资源和方法,这样前端应用的调用这些方法的请求将被传递给 Lambda 函数;而 Lambda 函数执行结束后,结果将返回给前端应用。其中,请求和响应内容均是按照预定义的 Body Mapping Templates 转换成 JSON 格式。


  • 创建一个新的 API,并定义 ”travelagency” 的资源,然后声明 GET 和 POST 两个方法,分别用于实现“查询旅行社“和”添加旅行社“的服务调用;

  • 在该资源的“Integration Request” 页面中配置与 Lambda 函数的集成方式(下图以 GET 方法为例);



  • 为 GET 方法定义 URL 查询字符串 “agencynum”,该字符串是查询请求的参数,例如:“/travelagency?agencynum=00000055”;



  • 为 GET 方法定义如下的 Body Mapping Template,从而 API Gateway 可以捕捉到请求里的必要参数信息并传递给 Lambda 函数,包括 SAP 应用的私网地址、端口、OData 服务路径、认证信息以及查询字符串“agencynum”



  • 为 POST 方法定义如下的 Body Mapping Template,其中,JSON 格式的 ”body” 是该方法的主要参数,定义了将要提交给 OData API 的数据,例如以下是待添加的旅行社信息:

  • Json


   {       "agencynum":"00133333",       "NAME":"ACME Holiday",       "STREET":"Jiuxianqiao Road",       "POSTCODE":"100000",       "CITY":"Beijing",       "COUNTRY":"CN",       "TELEPHONE":"010-88888888",       "URL":"http://www.acmeholiday.aws",       "LANGU":"CN",       "CURRENCY":"CNY",       "mimeType":"text/html"   }
复制代码


[](https://s3.cn-north-1.amazonaws.com.cn/awschinablog/amazon-lambda-sap(11).png)](https://s3.cn-north-1.amazonaws.com.cn/awschinablog/amazon-lambda-sap(11).png)
复制代码


  • 部署 API,并启用缓存功能,这样 API Gateway 将缓存请求的响应,从而降低对后台 SAP 应用的请求次数,并优化请求的响应延迟。


Lambda 函数的实现与部署

采用 Node.js 实现的 Lambda 函数负责:a). 接收 API Gateway 传递过来的请求和参数,根据不同的方法,转发给后台的 OData API endpoints;b). 针对 POST 方法,先调用 HTTP GET 方法请求 X-CSRF-Token 和 Cookie,然后调用 HTTP POST 方法提交待添加的数据;c). 将 OData API endpoints 的响应结果返回给 API Gateway。


  • 创建执行 Lambda 函数所需的 IAM 角色 “LambdaVpcProxyExecutionRole”,采用的权限策略如下:

  • Json


   {       "Version": "2012-10-17",       "Statement": [           {               "Effect": "Allow",               "Action": [                   "logs:CreateLogGroup",                   "logs:CreateLogStream",                   "logs:PutLogEvents"               ],               "Resource": "arn:aws-cn:logs:*:*:*"           },           {               "Effect": "Allow",               "Action": [                   "ec2:CreateNetworkInterface",                   "ec2:DescribeNetworkInterfaces",                   "ec2:DetachNetworkInterface",                   "ec2:DeleteNetworkInterface"               ],               "Resource": "*"           }       ]   }
复制代码


  • 创建 Lambda 函数 “sapapi-proxy”, 并赋予刚刚创建的 IAM 角色;

  • 配置 Lambda 函数访问的 VPC 信息,包括子网和安全组(注意:AWS 要求至少选择 2 个子网以在高可用性模式下运行 Lambda 函数);


  • 实现 Lambda 函数,以下是接收请求和返回响应的主函数体代码:

  • Js


   exports.handler = (event, context, callback) => {
const done = (err, res) => callback(null, { statusCode: err ? '400' : '200', body: err ? err.message : res, headers: { 'Content-Type': 'application/json', }, });
var endpoint = { host: event.requestParams.hostname, port: event.requestParams.port, path: event.requestParams.path, username: event.requestParams.username, password: event.requestParams.password };
switch (event.requestParams.httpMethod) { case 'GET': getTravelAgency(endpoint, event.requestParams.agencynum, done); break; case 'POST': postTravelAgency(endpoint, event.requestParams.body, done); break; default: done(new Error(`Unsupported methods "${event.requestParams.httpMethod}"`)); } };
复制代码


  • 处理 GET 方法的 “getTravelAgency” 函数代码如下图所示:

  • Js


   //return travel agency information based on parameters   //'use strict';   var http = require('http');
exports.getTravelAgency = (ep, params, callback) => {
if (params == "" ) callback(new Error("Parameter 'carrierid' has not been provided"));
var sAuth = 'Basic '; sAuth += new Buffer(ep.username + ':' + ep.password).toString('base64');
var headers = { 'Authorization': sAuth };
var options = { host : ep.host, port : ep.port, path : ep.path + "(\'"+ params+ "\')?$format=json", method : "GET", headers : headers };
var req=http.request(options,function(res){ res.setEncoding("utf-8"); var responseString = ''; res.on('data',function(chunk){ responseString += chunk; }); res.on('end', function () { callback(undefined, JSON.parse(responseString)); }); });
req.end();
req.on("error",function(err){ callback(new Error(err.message)); }); }
复制代码


  • 处理 POST 方法的 “postTravelAgency” 函数代码如下图所示:

  • Js


   //add new travel agency based on parameters   //'use strict';   var http = require('http');   var xml2js = require('xml2js');   //var sapapi = require('./sapapi');   //var extsys = require('./settings').extsys;
exports.postTravelAgency = (ep, data, callback) => {
//callback(new Error(JSON.stringify(data)));
if (data == "" ) callback(new Error("Parameter 'data' has not been provided"));
var sAuth = 'Basic '; sAuth += new Buffer(ep.username + ':' + ep.password).toString('base64');
var oGetRequest = new Promise(function (resolve, reject) { // body... var headers = { 'Authorization': sAuth, 'x-csrf-token': "fetch" };
var options = { host : ep.host, port : ep.port, path : ep.path, method : "GET", headers : headers };
//request x-csrf-token var req=http.request(options,function(res){ resolve(res); });
req.setTimeout(60000, function () { reject( new Error("Server is unreachable")); }); req.end(); req.on('error', function (error) { reject(error); }); });
oGetRequest.then( //resolve function (oGetRes) { //payload from request var dataString = JSON.stringify(data);
var headers = {}; headers['Authorization'] = sAuth; headers['Accept-Language'] = 'en'; headers['X-Requested-With'] = "XMLHttpRequest"; headers['Content-Type'] = 'application/json'; headers['X-CSRF-Token'] = oGetRes.headers['x-csrf-token']; headers['cookie'] = oGetRes.headers['set-cookie'];
var options = { host : ep.host, port : ep.port, path : ep.path, method : "POST", headers : headers };
var req = http.request(options, function (res) {
if (res.statusCode !== 201) return callback(new Error(res.statusCode));
res.setEncoding('utf-8');
var responseString = '';
res.on('data', function (data) { responseString += data; //callback(new Error(responseString)); });
res.on('end', function () { var parser = new xml2js.Parser(); //callback(undefined, parser.parseString(responseString)); callback(undefined, responseString); }); });
req.write(dataString); req.end(); req.on('error', function (error) { callback(new Error(error.message)); }); },
// reject function (err) { callback(new Error(err.message)); } ); }
复制代码


<pre>
</pre>
复制代码


测试

使用 Postman 对 API 进行测试,以下是调用 GET 方法即查询旅行社的测试结果。其中,”body” 是 SAP 返回的 JSON 格式的 OData 资源描述信息。



以下是调用 POST 方法即添加新旅行社的测试结果。其中,”body” 是 SAP 返回的 Atom 格式的 OData 资源描述信息。



总结

本文介绍了使用 API Gateway 与 Lambda 实现 SAP 应用的微服务,该方式无需将 OData API endpoints 暴露在公网,从而满足企业应用对于安全合规的要求;同时, Lambda 函数代理 CRSF 安全令牌的申请,为前端应用提供了更加透明的开发接口。


本示例在 API 调用请求中采用了基础的认证方式(即 HTTP 报文头中的 “Authorization” 字段),但是在生产环境中,建议采用 OAuth 2.0 的认证方式(例如在 Lambda 函数中实现这一认证授权的工作流程)。后续的博客文章将会展开介绍这部分工作。


致谢

感谢宁夏西云数据科技有限公司郭润平对本文示例环境 SAP S/4HANA 镜像的支持。


主要参考链接


作者介绍:


刘玉恒


AWS 资深顾问,拥有丰富的云计算架构咨询服务经验,现致力于企业客户应用迁移、容灾与双活解决方案。曾就职于 VMware 从事咨询服务顾问和技术客户经理等职位。


本文转载自 AWS 技术博客。


原文链接:


https://amazonaws-china.com/cn/blogs/china/aws-lambda-sap/


2019 年 10 月 22 日 08:00470

评论

发布
暂无评论
发现更多内容

测试开发之网络篇-常用服务协议

禅道项目管理

IP HTTP 协议

标准物模型:设备无缝对接,IOT界的福音

华为云开发者社区

物联网 IoT 物模型 标准物模型 IoT Stage

一文读懂云原生 go-zero 微服务框架

晨雨听风

GitHub Web Go 语言

再添新誉!浪潮云斩获年度领先品牌等多项殊荣

浪潮云

云计算

架构之:数据流架构

程序那些事

架构 系统架构 软件架构 程序那些事

云图说|数据仓库服务 GaussDB(DWS) 的“千里眼、顺风耳”—数据库智能运维

华为云开发者社区

数据库 数据仓库 GaussDB(DWS) 云图说 数据仓库服务

【架构师训练营】电商业务微服务拆分设计

eoeoeo

618技术特辑(三)直播带货王,“OMG买它”的背后,为什么是一连串技术挑战?

华为云开发者社区

CDN 直播 618 低时延 视频直播

Flink State 和 Fault Tolerance(二)

Alex🐒

flink 翻译 flink1.13

Cilium 首次集成国内云服务,阿里云 ENI 被纳入新版本特性

阿里巴巴云原生

容器 云原生

恭喜埃文科技入选“2021年中国网安产业潜力之星”!

郑州埃文科技

GraphQL 初探

wangwei1237

RESTful API graphql

2021中国边缘计算企业20强榜单出炉,EMQ强势入围!

EMQ映云科技

开源 边缘计算 计算 emq

OpenKruise :SidecarSet 助力 Mesh 容器热升级

阿里巴巴云原生

容器 云原生

好的目标管理:SMART原则

石云升

创业 职场经验 管理经验 6月日更

推理综艺的正确打开方式!爱奇艺玩转智能技术,“互动+内容”引爆迷综季

爱奇艺技术产品团队

Python——嵌套

在即

6月日更

react源码解析15.scheduler&Lane

全栈潇晨

React

【Flutter 专题】101 何为 Flutter Elements ?

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 6月日更

EasyRecovery Pro绿色破解版,免序列号激活

淋雨

数据恢复 EasyRecovery 文件恢复 Easyrecovery破解 恢复软件

有了这个组合拳,不再写bug

看山

DevOps 6月日更

HarmonyOS学习路之开发篇——Service Ability

爱吃土豆丝的打工人

Server HarmonyOS 路由 Ability Server

物联网发展,行业新领域

anyRTC开发者

音视频 WebRTC 智能硬件 智能安防 实时通讯

bzz节点挖矿分发系统开发案例

薇電13242772558

区块链

中年程序员转行第1年的感悟|2021 年中总结

王磊

Java 编程 编程之路 编程故事

如何有效地管理项目变更?

万事ONES

项目管理 研发管理 ONES

项目管理100问 | 一个完整的缺陷管理流程是什么样的?

万事ONES

项目管理 研发管理 bug ONES

618技术特辑(四)疯狂剁手的同时,电商隐私安全你注意到了吗?

华为云开发者社区

电商 数据安全 云安全 618 隐私安全

模块六作业

Chris Cheng

架构训练营

BoCloud博云获评2021云计算PaaS创新领导者

BoCloud博云

容器

WorkPlus即时通讯-通讯录功能大全

WorkPlus Lite

即时通讯 IM 移动开发 开源安全

企业应用上云的新花样:利用 Amazon API Gateway 和 AWS Lambda 实现 SAP 应用微服务化_语言 & 开发_亚马逊云科技 (Amazon Web Services)_InfoQ精选文章