今天的文章来自SAP成都研究院高级程序员、架构师李贝宁(Ben)。作为成都研究院精通Java、JavaScript、ABAP三种编程语言的几位同事之一,Ben先后担任成都CRMFiori开发团队、S4CRM开发团队和未发布云的架构师产品开发团队。Ben在这三个团队的职责是产品架构设计和部分功能代码的编写,以及组内其他同事的代码审查。除了在架构设计和编程方面的出色技能,Ben在传授知识和解惑方面也有丰富的经验。Ben是SAP研究院的敏捷软件工程教练,也是SAP成都研究院多个内部培训课程的讲师。他的课程帮助很多刚从大学毕业的年轻同事从在学校写玩具代码,走上真正的企业软件开发的专业道路。每个同时精通几种风格完全不同的编程语言的开发者,总是有自己的一套经验和方法,将这些语言整合为一门,以供自己使用。那么本是怎么做到的呢?或许可以从本的爱好中看出一丝端倪。本喜欢足球和围棋,水平在业余爱好者中不算太差。除了本,我能想到的仅有的两个爱好,谁能同时驾驭一刚一柔、一阴一阳二爱好:练过八掌外的英雄郭靖洪七公的造诣。岂料郭靖修炼九阴真经将近二十年,一开始还未显露真面目,降龙十八掌数十招之后,威力忽强忽弱,吞咽吐吐,从最严格到最强大。生柔妙用,是当年洪七公无法领悟的神功。2.周芷若,左手持短刀,右手持长鞭的峨眉美人头像。周芷若取出软鞭,右手一抖,鞭子顿时卷成十几个大大小小的圆圈,美极了,左手一翻,蓝光一闪,露出一个短刀。群雄昨日见识过她软鞭的威力,没想到她左手同时使刀,一长一短,一软一硬,完全是两种不同的武器。群雄赞叹之下,精神为之一振。3.天胃星九纹龙石津。水浒传中虽然有卢俊义、史文公、林冲等几位具有爆发力值的英雄,但他们在书中自始至终只使用一种武器。史大郎在战场上与人拼杀的时候,先后使用了三种不同的武器,其中就包括流星锤这种中国古代将领很少敢尝试的高难度武器。”史进怒道:“小偷竟敢如此猖狂!然后拿起三尖二刃四孔八环刀,直奔兰生而去。兰生连忙举起独足青铜人与史进对战。两人各显武功,奋勇作战。史进换上尖钢丈八蛇枪,骤然出手。哈云生见状,高高举起五股叉,冲上前去,直把史进给夹了。两人没有说话,两马交错,同时持枪,一回一回。只见石进的长枪,高高低低,前后左右,左冲右扫,身子上下摆动,满是枪影。还来不及说,但很快,史进已经提着流星锤冲到阵前,化作一匹高大的骏马。兰生飞青铜人大战,沙面二人齐聚。史进转动流星锤挡在三人面前。书中所说的施大郎,在八十万禁军教官王进的指导下,十八般武艺样样精通,果然名不虚传。而李北宁在SAP成都研究院分别使用Java、JavaScript和ABAP的三个开发团队中被任命为架构师,技术综合度不输史大郎。据我所知,李贝宁最喜欢的球星是被球迷称为“绝命三郎”、“钢铁侠”的内德维德。他喜欢他在球场上不惜体力奔跑的铁血作风。李贝宁希望自己在场上也能像内德维德一样,做一个拼命的三郎。杰瑞不是粉丝,但他只知道在我们的历史上也有一个走投无路的三郎:作为80后,杰瑞年轻时在这些卡上花了不少钱。如果您有相同的收藏爱好,欢迎后台交流。以下是李北宁的文字。*大家好,我叫李贝宁,大家也可以叫我Ben,目前在SAP成都研究院云产品项目组担任高级开发工程师和架构师。我于2009年加入SAP。在此之前,我在上海花旗集团软件中心工作了4年,从事银行系统开发。进入SAP后,我在SAP上海研究院工作了两年。11月底调到SAP成都研究院工作至今。算起来,我在成都待了快七年了。除了编程,我还有两个不可动摇的爱好,足球和围棋。水平可以算是社区里的明星和街头的业余爱好者。。。我觉得这两个东西一个可以保持身体活力,一个可以保持精神活力,所以我一直坚持的节奏每周踢一场足球,下几盘象棋,当然也用作工作之余的放松。*本文介绍的是SAPHybris在SAP云平台上开发的一款云产品使用的组件ApplicationRouter(以下简称AppRouter)。SCPAppRouter是SAPCloudPlatform(以下简称SCP)上的核心模块之一。作为一个独立运行在SCPCloudFoundry环境中的应用,主要支持以下两个核心功能:反向代理:将外部请求分发到SCPCloudFoundry环境中的不同应用。安全集成:与SCPCloudFoundry的核心安全组件UAA无缝集成,提供用户认证、会话管理等安全相关功能。说到这里,你可能马上会想到Nginx,一个优秀的开源web服务器,用来执行类似反向代理的功能。如果我的应用程序要使用Nginx,是否可以?事实上,SCP并不限制AppRouter的使用——它是一个完全开放的平台,你可以部署任何你想要服务于应用程序的组件,但是SAP已经在上面提供了一系列基础设施组件,这套SAP原生组件提供了更好的集成和协作,AppRouter就是其中之一。了解AppRouter技术选择AppRouter是使用Node.js构建的标准Web应用程序。众所周知,Node.js作为一个开放的技术环境,在构建基于HTTP的Web应用方面具有先天优势:简单、高效。而且,经过近几年的快速迭代和发展,Node.js已经非常成熟和稳定。再加上开源社区提供的丰富库,Node.js已经成为一个强大的服务器端应用程序开发环境。SAP选择了Node.js作为其云战略平台核心组件的技术栈。从这个选择中,我们也可以看出SAP的云战略正在逐步开放。你可能会问,Node.js是单线程模型,按照上面的例子图,部署在SCPCloudFoundry上的后端访问都是通过AppRouter访问的,这样会不会有性能问题?其实这是对Node.js运行时模型的误解。参考一张Node.js运行时架构图:Node.js只为应用端提供单线程编程模型,但其底层运行时架构并不是单线程模型。在Node.js中,各种HTTP访问、数据库读写、文件IO访问,都是以异步的方式委托给底层的V8引擎。主线程不会阻塞,底层V8引擎有非常强大的并发处理能力。能够通过事件轮询快速将各个事件的并发处理结果返回给主线程。只要大量的CPU操作(比如大规模的业务逻辑操作、科学计算等)不是在Node.js的主线程中进行,这样的Node.js应用就可以有很好的性能。AppRouter恰好具有上述典型特征:在用户认证中,将识别用户身份和权限的工作委托给CloudFoundryUAA,将业务请求转发给各个独立部署的CloudFoundry应用。HTTP参数的简单转换和校验,请求的转发,请求响应的返回。AppRouter上的路由(routing)通过定义一系列目的地来实现AppRouter上的路由。具体在AppRouter的xs-app.json中配置route和destination,在manifest.yml中配置destination对应的url:manifest.yml:简单说明一下主要参数:Routessource:可以是URL也可以是正则表达式,它定义了当前路由匹配什么样的请求路径。target:当前请求是如何处理的重写为目标地址destination:当前请求路由到manifest中的哪个目标地址。authenticationType:有三个选择,xsuaa、none和basic,xsuaa和none分别表示是否对当前请求在AppRouter上进行用户安全认证,下节会详细介绍。Basic在与SAPHANA集成时提供默认的安全身份验证支持。DestinationName:用于匹配xs-app.json中的destination配置URL:目标应用的真实ClouldFoundry地址ForwardAuthToken:如果请求中包含oauthtoken,是否将oauthtoken转发给目标应用。AppRouter还支持部分oauthtoken的验证功能,所以用户也可以根据具体情况选择不转发oauthtoken,在AppRouter端进行验证。除了基本的路由功能,AppRouter还提供丰富的Web应用相关的功能支持,如Connection管理、session管理、扩展http头、跨域、WebSocket等。AppRouter与SCPUAA的安全集成上一节提到,AppRouter在路由过程中提供了用户安全认证支持。配置路由的AuthenticationType为xsuaa,AppRouter会检查前端发送的请求是否有合法会话。如果没有,AppRouter会将用户引导至SCPUAA的用户认证界面。用户重新认证成功后,会生成一个新的合法session,并将这个session返回给前端应用。整个认证过程由SCPAppRouter和SCPUAA共同完成。SCPUAA是对SAP在CloudFoundry上提供的安全组件UAA(UserAccountandAuthenticationService)的封装。CloudFoundryUAA是一个实现了标准的Oauth2.0协议的授权服务器,SAP在此基础上做了一些自定义的增强,但是接口和原来的UAA是一致的,这样可以提供与OAuth客户端程序的兼容越多越好。CloudFoundryUAA官方文档:https://docs.cloudfoundry.org...SCP标准OAuth2.0流程:如果熟悉OAuth2.0协议,从这个流程图可以很快看出AppRouter和UAA的关系.它们之间的交互是通过AuthorizationCodeGrantFlow,在交互过程中分别扮演OAuthClient和OAuthServer的角色。关于OAuth2.0,请参考:https://oauth.net/2/看到这里你可能会问,为什么前端浏览器不作为??OAuthClient呢?除了安全方面的考虑,AppRouter对前端隐藏OAuth过程的另一个好处是,前端的各种应用不需要知道UAA上的ClientID和ClientSecret等细节,提供了更好的安全性。其次,还有SAP在产品层面的考虑。为了其标准产品UI技术的一致性,包括SCP在内的大部分产品都是基于SAPUI5构建前端UI,而UI5是基于HTML5技术。来吧,这些产品都是基于浏览器的富客户端应用程序。这样,在标准的AppRouter中实现OAuth2.0流程,可以让SAP的各种前端应用无需关注认证流程的细节。如上图所示,AppRouter在完成认证过程并最终拿到token后,并没有将token返回给浏览器。相反,它会在AppRouter上生成一个会话并将该会话与令牌相关联。在这里它起到了中介的作用,前端与session交互,后端与token交互。除了默认支持浏览器端应用,SCP作为一个开放平台当然也支持移动端原生应用的集成。我不会在这里详细介绍。详情请参考SCP的开发文档。AppRouter上的Session管理AppRouter上的session管理利用了Node.js的session-express框架,默认将session缓存在实例内存中(下图79行):然后采用sessionstickiness策略保证部署在多个实例中,在同一个session的情况下,同一个session的请求会发送到同一个instance,保证session可以继续。SessionStickiness:https://stackoverflow.com/que...这样做的好处是既利用了实例内存的高性能,又在一定程度上保证了高可靠性。但代价是牺牲了动态缩放的能力。AppRouter实例上一旦有活动会话,就无法关闭该实例。幸运的是,AppRouter使用了开源的express-session框架,它不仅仅将会话存储在实例内存中。Node.js开源社区提供了多种express-session外部存储方案。至少在技术上,AppRouter提供的实例内存存储可以替换为外部存储,无需太多的定制开发,从而使多个AppRouter实例可以共享同一套会话存储。AppRouter的可扩展性一提到SAP产品,可扩展性就是一个绕不开的话题,这是由SAP的业务面向企业级客户所决定的。SAP也一直致力于从平台到框架再到上层产品尽可能地为SAP客户提供良好的可扩展性。AppRouter也不例外,因为它直接使用了Node.js的connect框架,这是一个提供丰富扩展的中间件框架,能够以可插拔的方式为Node.js的请求和响应提供过滤。以及拦截,具体可以参考connect的主页。AppRouter基于connect。当然AppRouter的用户可以直接获取connect提供的各种中间件。另外AppRouter也提供了自己的一些中间件:是不是很简单直接?使用这些中间件无需修改本机AppRouter内的代码。AppRouter上的各种中间件这里就不一一赘述了。具体可以参考AppRouter的Github文档。综上所述,AppRouter是一个设计简单、使用方便、可扩展性好的反向代理组件。为SAP用户在SCP上开发应用提供了更多的选择和便利。谢谢阅读。获取更多Jerry原创技术文章,请关注微信公众号“汪子熙”。
