发明内容
本发明主要目的在于,提供一种复杂Web应用前端运行时分析方法,以解决现有的程序分析手段难以有效实现对Web应用前端JavaScript的分析的问题。
本发明是通过如下技术方案实现的:
一种复杂Web应用前端运行时分析方法,包括如下步骤:
步骤S1:利用运行时信息与分析结果采集工具,捕捉运行时信息并进行动态数据依赖关系分析,并采集运行记录日志、Source Maps以及动态数据依赖关系的分析结果;
步骤S2:根据所述运行记录日志、Source Maps以及动态数据依赖关系的分析结果,使用控制流与数据流可视化与分析工具对Web应用前端的控制流与数据流进行分析,得到获取所需数据或实现所需功能需要执行的网络请求以及JavaScript业务逻辑与数据处理逻辑,以及所述业务逻辑与数据处理逻辑之间的串联关系。
进一步地,所述运行记录日志保存在数据库中,记录了Web应用前端的控制流信息、UI与网络事件及其相关的数据;
所述Source Maps以JSON格式记录了运行记录日志的ID与Web应用原JavaScript代码相应位置之间的映射关系;
所述动态数据依赖关系的分析结果保存在文件中,以JSON格式记录了运行记录日志中所记录的JavaScript操作与数据之间的动态数据依赖关系。
进一步地,所述运行时信息与分析结果采集工具的前端包括Web应用前端运行时分析程序、Web应用插装模块、代理服务器,所述运行时信息与分析结果采集工具的后端包括WebSocket服务器、数据库更新模块、文件更新模块;
所述Web应用前端运行时分析程序以所述运行记录日志的方式记录所述Web应用前端的控制流信息、UI与网络事件及其相关的数据,并分析所述运行记录日志中所记录的JavaScript操作与事件之间的动态数据依赖关系;
所述代理服务器用于截获浏览器与Web应用服务器之间所有HTTP请求与响应,并发送给所述Web应用插装模块;
所述Web应用插装模块通过对JavaScript代码进行插桩的方式将所述Web服务运行时环境和Web应用前端运行时分析程序插入所述Web应用前端;
所述WebSocket服务器用于接收Web应用前端运行时分析程序发送的运行时信息与分析结果;
所述数据库更新模块用于将运行记录日志写入到日志数据库中;
所述文件更新模块用于将JSON格式的Source Maps与动态数据依赖关系的分析结果序列化并保存到文件中。
进一步地,所述步骤S1包括:
启动所述代理服务器,并设置其将所截获的HTTP请求与响应发送给所述Web应用插装模块处理,同时启动所述运行时信息与分析结果采集工具;
在浏览器中设置代理到所述代理服务器所监听的端口,访问所需服务化的Web应用并进行操作,使得界面中显示所需服务化的数据或完成所需服务化的功能,该过程中,所述代理服务器截获所有HTTP请求与响应,并发送给所述Web应用插装模块处理,若所请求的资源为HTML或JavaScript文件,则所述Web应用插装模块对所述Web应用前端进行插桩,插入所述Web应用插装模块的运行时环境与Web应用前端运行时分析程序;
在所述Web应用前端运行时,所述Web应用前端运行时分析程序执行分析,捕捉所述Web应用前端的运行时信息并进行动态数据依赖关系分析,并采集运行记录日志、SourceMaps以及动态数据依赖关系的分析结果。
进一步地,所述Web应用前端运行时分析程序采用基于资源URL与基于数据搜索相结合的方式过滤掉所述运行记录日志中的无用运行记录。
进一步地,所述控制流与数据流可视化与分析工具的前端包括运行记录的可视化查看器、代码与数据查看器、数据流分析模块,控制流与数据流可视化与分析工具的后端包括数据服务器、数据库读取模块、文件读取模块;
所述运行记录的可视化查看器以可折叠的树型结构呈现所述Web应用前端的控制流;
所述代码与数据查看器用于格式化并显示运行记录日志中所记录的操作对应的Web应用原JavaScript代码位置与相关数据;
所述数据流分析模块基于动态数据依赖图与基于数据搜索两种数据流分析方式对数据流进行分析,以得到获取所需数据或实现所需功能需要执行的网络请求以及JavaScript业务逻辑与数据处理逻辑;
所述数据库读取模块用于从日志数据库读取运行记录日志;
所述文件读取模块用于从文件中读取Source Maps与动态数据依赖关系的分析结果;
所述数据服务器用于向前端Web界面提供运行记录日志、Source Maps与动态数据依赖关系的分析结果。
进一步地,所述步骤S2包括:
启动所述控制流与数据流可视化与分析工具的后端,并通过浏览器访问所述控制流与数据流可视化与分析工具的前端Web界面;
所述数据服务器通过所述数据库读取模块读取所述运行记录日志,通过所述文件读取模块读取所述Source Maps与动态数据依赖关系的分析结果,并将所述运行记录日志、所述Source Maps与动态数据依赖关系的分析结果发送给所述控制流与数据流可视化与分析工具的前端Web界面;
所述前端Web界面以可视化的方式呈现所述Web应用前端的控制流,同时数据流分析模块基于动态数据依赖图与基于数据搜索两种数据流分析方式对数据流进行分析,得到获取所需数据或实现所需功能需要执行的网络请求以及JavaScript业务逻辑与数据处理逻辑,以及所述业务逻辑与数据处理逻辑之间的串联关系。
进一步地,所述动态数据依赖图根据运行记录日志中所记录的JavaScript操作与事件之间的动态数据依赖关系构建而成。
与现有技术相比,本发明提供的复杂Web应用前端运行时分析方法,利用运行时信息与分析结果采集工具,捕捉运行时信息并进行动态数据依赖关系分析,并通过控制流与数据流可视化与分析工具对Web应用前端的控制流与数据流进行分析,以辅助开发者快速、高效地分析与理解复杂Web应用前端的控制流与数据流,得到获取所需数据或实现所需功能需要执行的网络请求以及JavaScript业务逻辑与数据处理逻辑,以及所述业务逻辑与数据处理逻辑之间的串联关系,为后续Web应用服务化过程中对Web应用前端JavaScript业务逻辑与数据处理逻辑的提取与重构奠定了基础。
具体实施方式
为使本发明的目的、技术方案和优点更加清楚明白,下面结合实施例和附图,对本发明作进一步详细说明。
本发明面向复杂Web应用的服务化方法总体概述:
本发明提供的面向复杂Web应用的服务化方法,分别从复杂Web应用服务化的分析理解与开发运行两个阶段入手,辅助实现复杂Web应用的服务化。分析理解阶段的目标是辅助快速、高效地分析与理解复杂Web应用前端的控制流与数据流,并梳理出获取所需数据或实现所需功能需要执行的网络请求以及JavaScript业务逻辑与数据处理逻辑,以及业务逻辑与数据处理逻辑之间的串联关系,为此本发明设计了Web应用前端运行时分析工具。开发运行阶段的目标是辅助快速、高效地完成Web服务的开发,并对服务化所得到的Web服务提供可靠的运行时支持,为此本发明提出了Web应用前端JavaScript业务逻辑与数据处理逻辑提取与重构方案,并设计了支持HTML与DOM API(Document Object Model ApplicationProgramming Interface,文档对象模型应用程序编程接口)的Web服务运行时环境。
在进行本发明方法的总体设计时,考虑了以下几点高层要求,这些要求指导了本发明方法设计的选择:
1).最小化工作量。
在分析理解阶段,本发明提供了控制流与数据流可视化与分析工具,能够直观的呈现Web应用前端运行时的控制流与数据流及其分析结果,并提供了基于动态数据依赖图与基于数据搜索两种数据流分析方式;在开发运行阶段,本发明提供了Web应用前端JavaScript业务逻辑与数据处理逻辑的提取与重构方案,以及支持HTML与DOM API的Web服务运行时环境,能够结合Web应用前端运行时分析工具的分析结果,以较小的代价完成Web应用前端JavaScript业务逻辑与数据处理逻辑的提取与重构,并保证所提取的JavaScript业务逻辑与数据处理逻辑能够在服务器端正确运行。
2).良好的适用性与兼容性。
本发明选择通过基于所述Web应用插装模块对JavaScript代码进行插桩的方式,而非修改浏览器等方式来实现Web应用前端运行时分析工具,从而实现了对浏览器与JavaScript引擎的独立性,使本发明的方法具有良好的适用性与兼容性。另外,本发明选择基于跨平台的JavaScript运行时环境Node.js实现Web服务运行时环境,从而支持了跨平台。
3).服务化所得到的Web服务具有良好的性能、延迟与可扩展性。
本发明选择基于轻量级的HTML与DOM标准的JavaScript实现来实现Web服务运行时环境,避免了浏览器内核所进行的布局、渲染等一系列操作的巨大开销,从而保证了Web服务具有良好的性能、延迟与可扩展性。
参见图5、图6,本发明面向复杂Web应用的服务化方法的主要流程包括以下五个步骤,其中前两个步骤属于复杂Web应用前端运行时分析方法的步骤,属于分析理解阶段,后三个步骤属于开发运行阶段:
步骤S1:利用运行时信息与分析结果采集工具,捕捉运行时信息并进行动态数据依赖关系分析,并采集运行记录日志、Source Maps以及动态数据依赖关系的分析结果;
具体可通过插桩方式将Web服务运行时环境和Web应用前端运行时分析程序插入Web应用前端,并执行分析程序以捕捉Web应用前端的运行时信息并进行动态数据依赖关系分析。首先,启动代理服务器,并设置其将所截获的HTTP请求与响应发送给Web应用插装模块处理,同时启动运行时信息与分析结果采集工具。然后,在浏览器中设置代理到代理服务器所监听的端口,访问所需服务化的Web应用并进行操作,使得界面中显示所需服务化的数据或完成所需服务化的功能,该过程中,代理服务器截获所有HTTP请求与响应,并发送给Web应用插装模块处理,若所请求的资源为HTML或JavaScript文件,则Web应用插装模块对Web应用前端进行插桩,插入所述Web应用插装模块的运行时环境与Web应用前端运行时分析程序。Web应用插装模块可通过对JavaScript代码进行插桩的方式将Web服务运行时环境和Web应用前端运行时分析程序插入Web应用前端。因此,代理服务器返回给浏览器并加载运行的是插桩后的HTML与JavaScript文件。在Web应用前端运行时,Web应用前端运行时分析程序执行分析,捕捉Web应用前端的运行时信息并进行动态数据依赖关系分析,并采集运行记录日志、Source Maps以及动态数据依赖关系的分析结果。所采集的数据将通过WebSocket协议发送给采集服务器并保存到数据库与文件中。该步骤的运行时结构如图1所示。
步骤S2:根据运行记录日志、Source Maps以及动态数据依赖关系的分析结果,使用控制流与数据流可视化与分析工具对Web应用前端的控制流与数据流进行分析,得到获取所需数据或实现所需功能需要执行的网络请求以及JavaScript业务逻辑与数据处理逻辑,以及业务逻辑与数据处理逻辑之间的串联关系。
首先,启动控制流与数据流可视化与分析工具的后端,并通过浏览器访问控制流与数据流可视化与分析工具的前端Web界面。然后,数据服务器通过数据库读取模块读取运行记录日志,通过文件读取模块读取Source Maps与动态数据依赖关系的分析结果,并将运行记录日志、Source Maps与动态数据依赖关系的分析结果发送给控制流与数据流可视化与分析工具的前端Web界面。前端Web界面以可视化的方式呈现Web应用前端的控制流,同时数据流分析模块基于动态数据依赖图与基于数据搜索两种数据流分析方式对数据流进行分析,得到获取所需数据或实现所需功能需要执行的网络请求以及JavaScript业务逻辑与数据处理逻辑,以及业务逻辑与数据处理逻辑之间的串联关系。该步骤的运行时结构如图2所示。
步骤S3:根据步骤S2的分析结果,在Web应用前端JavaScript代码中定位所需JavaScript业务逻辑与数据处理逻辑,并对所需JavaScript业务逻辑与数据处理逻辑进行提取与重构。
步骤S4:构造Web服务处理程序,根据步骤S2得到的Web应用前端的逻辑顺序,执行获取所需数据或实现所需功能需要执行的网络请求,并通过Web服务运行时环境中的支持HTML与DOM API的JavaScritp运行时环境来执行步骤S3中所提取的JavaScript业务逻辑与数据处理逻辑,并将它们串联,得到Web服务处理程序。至此完成Web服务的开发。
步骤S5:将步骤S4中得到的Web服务处理程序部署到Web服务运行时环境中运行。至此完成了对该Web应用中的所需数据或功能的服务化。
以下针对上述各步骤,对本发明进行详细阐述。
1.Web应用前端运行时分析工具(Web Application Frontend Runtime AnalysisTool)的设计
Web应用前端运行时分析工具概述:Web应用前端运行时分析工具的作用是在复杂Web应用服务化的分析理解阶段,辅助快速、高效地分析与理解复杂Web应用前端的控制流与数据流,并梳理出获取所需数据或实现所需功能需要执行的网络请求以及JavaScript业务逻辑与数据处理逻辑,以及业务逻辑与数据处理逻辑之间的串联关系。本发明选择采用运行时动态分析的方式,辅助分析与理解Web应用前端的控制流与数据流。具体来说,该分析工具基于代理服务器与所述Web应用插装模块,在运行时动态地对Web应用前端JavaScript代码进行插桩,通过运行插桩后的代码捕捉其中的控制流信息并进行动态数据依赖关系分析,最后在此基础上提供了基于Web的控制流与数据流可视化与分析工具。
1.1:Web应用前端运行时分析工具的架构
Web应用前端运行时分析工具的框架如图3所示,主要包括两个部分——运行时信息与分析结果采集工具(Runtime Information and Analysis Result Collector),以及控制流与数据流可视化与分析工具(Control Flow and Data Flow Visualiazation andAnalysis Tool)。
运行时信息与分析结果采集工具分为前端(Frontend)与后端(Backend)。运行时信息与分析结果采集工具的前端包括Web应用前端运行时分析程序、Web应用插装模块和代理服务器。其中最重要的部分是通过插桩方式插入所需服务化的Web应用前端HTML与JavaScript文件中的Web应用前端运行时分析程序(Web Application Instrumented withAnalysis)。该分析程序基于所述Web应用插装模块实现,并通过Web应用插装模块插入Web应用前端。最后,通过代理服务器代理服务器实现运行时的实时插桩。具体来说,代理服务器截获浏览器与Web应用服务器之间所有HTTP请求与响应,并发送给Web应用插装模块,若所请求的资源为HTML或JavaScript文件,则对Web应用前端进行插桩,插入所述Web应用插装模块的运行时环境与分析程序,并返回给浏览器加载运行。插桩后的Web应用前端在正常展示数据与完成功能的同时,还会执行分析程序,捕捉运行时信息并进行动态数据依赖关系分析,并采集运行记录日志、Source Maps以及动态数据依赖关系的分析结果。所采集的数据将通过WebSocket协议发送给后端的运行时信息与分析结果采集服务器。
运行时信息与分析结果采集工具的后端包括WebSocket服务器(WebSocketServer)、数据库更新模块(DB Updater)和文件更新模块(File Updater)。其中,WebSocket服务器(WebSocket Server)负责接收Web应用前端运行时分析程序发送的运行时信息与分析结果,数据库更新模块(DB Updater)负责将运行记录日志(Traces)写入到日志数据库中,文件更新模块(File Updater)负责将JSON(JavaScript Object Notation,JS对象简谱)格式的Source Maps与动态数据依赖关系的分析结果(Analysis Results)序列化并保存到文件中。
运行记录日志(Traces)、Source Maps与动态数据依赖关系的分析结果(AnalysisResults)是运行时信息与分析结果采集工具的产品,以及控制流与数据流可视化与分析工具的输入。运行记录日志保存在数据库中,记录了Web应用前端的控制流信息、UI(用户界面)与网络事件及其相关的数据,包括函数调用、变量读写、运算操作、条件分支、鼠标点击、Ajax请求发送与完成等。Source Maps以JSON格式记录了运行记录日志的ID与Web应用原JavaScript代码相应位置之间的映射关系。动态数据依赖关系的分析结果保存在文件中,以JSON格式记录了运行记录日志中所记录的JavaScript操作与数据之间的动态数据依赖关系。
控制流与数据流可视化与分析工具基于Web实现,分为前端(Frontend)与后端(Backend)。控制流与数据流可视化与分析工具的后端包括数据库读取模块(DB Reader)、文件读取模块(File Reader)和数据服务器(Data Server)。其中,数据库读取模块(DBReader)负责从日志数据库读取运行记录日志,文件读取模块(File Reader)负责从文件中读取Source Maps与动态数据依赖关系的分析结果,数据服务器(Data Server)负责向前端Web界面提供运行记录日志、Source Maps与动态数据依赖关系的分析结果。
控制流与数据流可视化与分析工具的前端Web界面包括运行记录的可视化查看器(Trace Visualization)、代码与数据查看器(Code and Data Inspector)和数据流分析模块(Data Flow Analysis)。其中,运行记录的可视化查看器(Trace Visualization)以可折叠的树型结构直观地呈现Web应用前端的控制流,代码与数据查看器(Code and DataInspector)能够格式化并显示运行记录日志中所记录的操作对应的Web应用原JavaScript代码位置与相关数据,并支持高亮显示搜索结果,数据流分析模块(Data Flow Analysis)基于动态数据依赖图与基于数据搜索两种数据流分析方式对数据流进行分析。
1.2.Web应用前端运行时分析程序的设计
Web应用前端运行时分析程序基于所述Web应用插装模块实现,并通过插桩方式插入所需服务化的Web应用前端。主要包含两个功能,一是以运行记录日志的方式记录Web应用前端的控制流信息、UI与网络事件及其相关的数据,二是分析运行记录日志中所记录的JavaScript操作与事件之间的动态数据依赖关系。
1.2.1.运行记录日志
Web应用前端运行时分析程序通过所述Web应用插装模块的运行时环境提供的一系列回调函数,捕捉所需服务化的Web应用前端JavaScript进行的各种操作及其相关的数据,并以日志的方式记录。一条运行记录日志通常包含操作发生的时间戳、操作的唯一标识符和与操作相关的数据。
除了通过所述Web应用插装模块提供的一系列回调函数来捕捉Web应用前端JavaScript进行的各种操作及其相关的数据以外,分析程序还通过各种方式来捕捉Web应用前端发生的UI事件以及网络事件。例如,对于鼠标点击事件,需要通过多种方式来捕捉。当点击事件的监听器是以HTML元素的onclick属性的方式直接嵌入在HTML代码中时,所述Web应用插装模块会将该监听器代码作为一个单独的JavaScript文件处理,因此分析程序通过在scriptEnter回调函数中检查调用栈的深度以及栈底栈帧的函数名是否为onclick来判断鼠标点击事件,并通过onclick函数的调用参数来得到所点击HTML元素的相关数据。而当点击事件的监听器是以DOM API addEventListener函数注册时,则需要在invokeFunPre与functionEnter回调函数中通过检查被调用函数的调用参数是否为MouseEvent类型且其type属性是否为“click”来判断鼠标点击事件,并从该MouseEvent对象中得到所点击HTML元素的相关数据。又如,对于Ajax请求相关的事件,通过包装并替换这些原生方法来捕捉Ajax请求的open与send事件,在替换后的这些方法中首先记录事件与相关数据,之后调用被替换的原生方法,以保证网络请求仍然能够正确执行。而对于Ajax请求的load事件,则同样采用了在invokeFunPre与functionEnter回调函数中检查被调用函数的调用参数的方法。
分析程序所记录的操作与事件类型主要包括:JavaScript文件开始执行、JavaScript文件结束执行、函数调用之前、函数调用之后、函数体开始执行、用return语句返回值、函数体结束执行、读取变量、写入变量、读取对象属性、写入对象属性、定义函数、创建字面量、二元操作、一元操作、检查分支条件、鼠标点击事件、Ajax请求open事件、Ajax请求send事件、Ajax请求load事件等。具体如下表1:
表1:分析程序所记录的操作与事件类型
分析程序提供了基于资源URL的过滤机制,可以在运行插桩后的Web应用之前,在浏览器控制台中调用分析程序所提供的API添加允许采集运行记录日志或需要排除的HTML与JavaScript资源的URL,以减少所得到的运行记录日志中的无用记录和提高Web应用采集运行记录日志以及进行动态数据依赖关系分析的性能。
分析程序还提供了基于数据搜索的过滤机制,可以在运行插桩后的Web应用之前,在浏览器控制台中调用分析程序所提供的API添加需要搜索的数据,以减小运行记录日志的数据传输量,提高Web应用的性能。基于数据搜索的过滤条件分为输入值与结果值两类。输入值类的过滤条件适合用于根据已知来源的值找到该值在Web应用前端JavaScript的控制流中第一次使用的位置,例如用户在界面中输入的用户名与密码。输入值类的过滤条件会在以下位置搜索:函数的调用参数、变量读取的值、对象属性读取的值、运算操作的操作数、分支条件的值、鼠标点击的HTML元素的标签名、id与class属性、以及所包含的文本、Ajax请求的HTTP方法、初始URL与请求体。结果值类的过滤条件适合用于根据未知来源的值找到该值在Web应用前端JavaScript控制流中第一次产生的位置。结果值类的过滤条件会在以下位置搜索:函数调用返回值、变量写入的值、对象属性写入的值、创建的字面量的值、运算的结果、Ajax请求重定向后的最终URL与响应内容。
在分析程序中维护了一个记录JavaScript控制流的多层树型结构,每个树节点代表一个操作记录,只有所有JavaScript文件开始执行与函数调用操作以及搜索到所添加的过滤条件数据的其他类型操作的记录会被添加到该树型结构中,其他操作记录会被立刻丢弃,以降低内存占用,提高Web应用性能。一个JavaScript文件开始执行或一个函数被调用时其文件或函数体中的语句触发的操作所对应的树节点将成为该操作所对应的树节点的子节点,当一个JavaScript文件结束执行或一次函数调用返回时,除非该操作的相关数据中搜索到所添加的过滤条件数据,或者该操作所对应的树节点至少存在一个子节点,否则即可删除该树节点以释放该操作记录所占用的内存。最终,对插桩后的Web应用完成操作后,分析程序将按照深度顺序遍历该树型结构,并将树节点所对应操作的运行记录日志传输到采集服务器。这种方式可以有效保持较低的内存占用,使插桩后的Web应用能够流畅运行。
在运行插桩后的Web应用采集运行记录日志时,上述基于URL与基于数据搜索两种过滤机制也可以同时配合使用,即,Web应用前端运行时分析程序采用基于资源URL与基于数据搜索相结合的方式过滤掉运行记录日志中的无用运行记录,以达到更好地过滤运行记录的效果。
1.2.2.动态数据依赖关系分析
Web应用前端运行时分析程序的另一个重要功能是分析所采集的运行记录日志中所记录的JavaScript操作与事件之间的动态数据依赖关系。首先,其分析的粒度是JavaScript中的基本操作而不是代码语句,一个语句可能对应多个基本操作,因此其分析结果可以映射到以语句为粒度的分析结果,是以语句为粒度的分析结果的超集。此外,同一个语句所包含的每一个基本操作的每次执行都对应一条不同的运行记录,因此分析程序可以完整地分析该操作在每次被执行时的真实数据依赖关系。
分析程序采用了影子值(Shadow Value)与影子控制流机制来跟踪JavaScript的动态数据流,以实现动态数据依赖关系的分析。一个操作所产生的结果值只直接依赖于该操作本身,因此一般情况下,分析程序在该结果值对应的Val类型的包装值的deps属性中只保存该操作的TID这一个数据依赖关系,这样在分析结果中也会得到使用该包装值作为输入的操作也直接依赖于产生该包装值的操作。间接数据依赖关系可以通过沿着操作之间的数据依赖关系链进行遍历得到,而在分析过程中只计算与保存直接数据依赖关系可以提高分析性能以及节省空间开销。然而,对于前述两种过滤机制所过滤的大量操作,保存其数据依赖关系反而会大幅增加空间开销,但是这些被过滤的操作仍然可能会在未被过滤的操作之间传递数据依赖关系。因此,对于这些被过滤的操作,分析程序并不会将其TID添加到所产生的结果值所对应的包装值的deps属性中,且通过作为该操作输入的包装值计算得到该操作所依赖的操作集合后,并不保存该分析结果,而是将这些所依赖的操作的TID添加到包装值的deps属性中,以将间接数据依赖信息继续传递给后续使用该包装值作为输入的操作。这样,最终的数据依赖关系分析结果中不包含被过滤的操作,却保留了通过这些操作所传递的间接数据依赖关系。
对于所有基本的JavaScript操作,定义了通过作为其输入的Val类型的包装值的deps属性计算该操作的数据依赖关系的规则,Web应用原JavaScript代码中的复杂语句都会被所述Web应用插装模块的运行时环境拆分并以基本操作为单元执行。以下是对于各类型的操作计算其数据依赖关系的规则,其中所述Web应用插装模块提供的回调函数的参数不加说明都为包装值:
函数调用
在运行记录日志中,一次函数调用操作分为“函数调用之前”与“函数调用之后”两个类型的两条记录,在分析数据依赖关系时也将它们分开分析,以分别分析函数调用本身的数据依赖关系以及函数调用的返回值的数据依赖关系。
“函数调用之前”记录用于分析函数调用本身的数据依赖关系,用于分析的所述Web应用插装模块的回调函数为invokeFunPre,所用参数为被调用的函数对象f、该次函数调用中this变量的值base、以及该次函数调用的参数arg1,arg2,…,argn,其依赖操作的集合deps的计算规则如下:
deps=getDeps(f)∪getDeps(base)∪
getDeps(arg1)∪getDeps(arg2)∪…∪getDeps(argn)
“函数调用之后”记录用于分析函数调用的返回值的数据依赖关系,用于分析的所述Web应用插装模块的回调函数为invokeFun,所用参数为函数调用的返回值result。对于该回调函数,需要分为两种情况讨论。若所调用函数为在JavaScript文件中定义的函数,则其函数体也会被Web应用插装模块所插桩,从而其中的操作也会触发所述Web应用插装模块提供的回调方法,将操作的结果值包装并替换为包装值,因此该函数调用的返回值result是一个包装值,其所依赖操作的集合deps的计算规则如下:
deps=getDeps(result)
然而,若所调用函数为浏览器所提供的原生函数,则Web应用插装模块无法对其函数体进行插桩,从而其返回值result是一个真实值。对此,只能假设对于浏览器所提供的原生函数,其调用的返回值依赖且仅依赖于该次调用的参数与this变量的值,通常情况下该假设是成立的。由于与该“函数调用之后”记录对应的“函数调用之前”记录已经依赖于该次调用的参数与this变量的值,因此只要直接使该“函数调用之后”记录依赖于所对应的“函数调用之前”记录即可。假设该“函数调用之后”记录的TID为“if12:34:5”,则知道与其对应的“函数调用之前”记录的TID为“ip12:34:5”,其所依赖操作的集合deps[if12:34:5]的计算规则如下:
deps[′if12:34:5′]=deps[′ip12:34:5′]
用return语句返回值
用于分析该操作的所述Web应用插装模块的回调函数为_return,所用参数为返回值val,其所依赖操作的集合deps的计算规则如下:
deps=getDeps(val)
读取变量
用于分析该操作的所述Web应用插装模块的回调函数为read,所用参数为所读取的值val,其所依赖操作的集合deps的计算规则如下:
deps=getDeps(val)
写入变量
用于分析该操作的所述Web应用插装模块的回调函数为write,所用参数为所写入的值val,其所依赖操作的集合deps的计算规则如下:
deps=getDeps(val)
读取对象属性
用于分析该操作的所述Web应用插装模块的回调函数为getFieldPre,所用参数为读取其属性的对象base以及所读取的属性名offset。分析读写对象属性操作的数据依赖关系较为复杂。首先,在前端JavaScript中window对象的属性等价于同名的全局变量。
因此,若读取其属性的对象为window,该操作应该作为读取变量操作处理,唯一不同的是在变量读取操作中变量名是写在JavaScript代码中的常量,而在读取window对象属性的操作中,属性名既可能是以window.property形式写在JavaScript代码中的常量,也可能是以window[property]形式指定的,而其中的property可能是计算出来的值,存在数据依赖。因此,其所依赖操作的集合deps的计算规则如下:
deps=getDeps(offset)∪getDeps(window[unwrap(offset)])
若读取其属性的对象不是window,则情况更为复杂。当一个操作使用从一个对象读取的一个属性作为其输入时,不希望得到的分析结果是该操作依赖于所有对该对象的任何一个属性进行最后一次写入的操作,而希望得到更精确的结果,即该操作仅依赖于产生该对象本身的操作、该操作所读取的属性名、以及对该属性进行最后一次写入的操作。因此,需要对象的包装值的deps属性中只保存产生该对象本身的操作的TID,而不包扩对其属性进行写入的操作的TID,对其不同属性进行最后一次写入的操作的TID则都需要分开保存在其他地方。为此,在每一个真实对象中维护了一个特殊属性SHADOW_PROPERTIES,其值为一个对象,称其为影子属性对象。对于原真实对象的每一个原有属性,在其影子属性对象中也维护一个同名属性,其值为该原有属性的包装值。
有了SHADOW_PROPERTIES属性之后,就可以精确地分析出读取属性操作所依赖操作的集合deps了:
deps
=getDeps(base)∪getDeps(offset)
∪getDeps(unwrap(base)[SHADOW_PROPERTIES][unwrap(offset)])
写入对象属性
用于分析该操作的所述Web应用插装模块的回调函数为putFieldPre,所用参数为写入其属性的对象base、所写入的属性名offset、以及所写入的值val,其所依赖操作的集合deps的计算规则如下:
deps=getDeps(base)∪getDeps(offset)∪getDeps(val)
除了,分析写入对象属性操作所依赖操作的集合以外,在putFieldPre回调函数中,还需要更新base对象的属性名offset对应的属性,以及base对象的SHADOW_PROPERTIES属性值即影子属性对象中的对应属性。具体操作如下:
base′=unwrap(base)
offset′=unwrap(offset)
base′[offset′]=unwrap(val)
base′[SHADOW_PROPERTIES][offset′]=vr
定义函数
用于分析该操作的所述Web应用插装模块的回调函数为declare,所用参数为所定义的函数对象val,由于该值在declare回调函数被调用之前刚刚由所述Web应用插装模块的运行时环境通过执行原JavaScript代码产生,还未经过分析程序的包装,因此是一个未经包装的真实值。该操作本身不依赖于其他操作,但是需要在declare回调方法中用包装值vr对所定义的函数对象val进行包装,并将该操作的TID添加到vr的deps属性中,以传递给后续使用所定义的函数作为输入值的操作。
创建字面量
用于分析该操作的所述Web应用插装模块的回调函数为literal,所用参数为所创建的字面量的值val,由于该值在literal回调函数被调用之前刚刚由所述Web应用插装模块的运行时环境通过执行原JavaScript代码产生,还未经过分析程序的包装,因此是一个未经包装的真实值。该操作本身也不依赖于其他操作,但是需要在literal回调方法中用包装值vr对所创建的字面量val进行包装,并将该操作的TID添加到vr的deps属性中,以传递给后续使用所创建的字面量作为输入值的操作。
另外,对于所创建的字面量为对象字面量(Object Literal)的情况,所述Web应用插装模块的运行时环境会从最内层属性的创建开始,触发多次literal回调函数。在内层属性的创建触发的literal回调函数中,会将所创建的字面量包装并替换为Val类型的包装值,因此会出现外层对象的创建所触发的literal回调函数中val对象的属性值为包装值的情况,导致在将该对象作为参数传递给浏览器所提供的原生函数之前,需要递归地对该对象的每一层属性调用unwrap函数进行处理。由于Web应用前端JavaScript中通常有大量嵌套层数非常多的对象,这种方式会严重影响插桩后的Web应用的运行性能。为此,为了与前文的对象的SHADOW_PROPERTIES属性机制进行统一,还需要针对所创建的的字面量为对象字面量的情况进行特殊处理,将其每一个属性值从包装值替换为所包装的真实值,并将该包装值保存到该对象的SHADOW_PROPERTIES属性值,即影子属性对象的同名属性中。
二元操作
用于分析该操作的所述Web应用插装模块的回调函数为binaryPre,所用参数为左操作数left与右操作数right,其所依赖操作的集合deps的计算规则如下:
deps=getDeps(left)∪getDeps(right)
一元操作
用于分析该操作的所述Web应用插装模块的回调函数为unaryPre,所用参数为操作数left,其所依赖操作的集合deps的计算规则如下:
deps=getDeps(left)
检查分支条件
用于分析该操作的所述Web应用插装模块的回调函数为conditional,所用参数为条件表达式的值result,其所依赖操作的集合deps的计算规则如下:
deps=getDeps(result)
Ajax请求open事件
Ajax请求的open与send事件是通过包装并替换XMLHttpRequest类型的默认事件监听器open与send方法来捕捉的,在替换后的这些方法中同时也会对其数据依赖关系进行分析。XMLHttpRequest类型的open方法是open事件的默认监听器,分析所用的方法参数为HTTP方法method与请求地址url,open事件所依赖操作的集合deps的计算规则如下:
deps=getDeps(method)∪getDeps(url)
Ajax请求send事件
XMLHttpRequest类型的send方法是send事件的默认监听器,分析所用的方法参数为HTTP请求体data,send事件所依赖操作的集合deps的计算规则如下:
deps=getDeps(data)
值得说明的是,由于JavaScript的内建操作无法在Val类型的包装值上正确执行,为了保证程序的正确性,在分析程序中除了对新产生的真实值进行包装并替换以外,还需要对传递给JavaScript内建操作的值进行unwrap操作,使得JavaScript的内建操作在真实值而不是包装值上执行。
1.3.控制流与数据流可视化与分析工具的设计
控制流与数据流可视化与分析工具的后端主要负责从数据库与文件中读取运行时信息与分析结果采集工具所采集到的数据并提供给前端Web界面,功能较为简单。因此,此处将重点介绍前端Web界面。
1.3.1.界面布局与基本功能:
控制流与数据流的可视化与分析工具的Web界面的默认布局分为左侧、右侧上方与右侧下方三个面板,各个面板的尺寸可以通过拖动面板之间的分隔条来调整。其中左侧面板为运行记录查看器,通过解析运行记录日志构建的Web应用前端控制流的树型结构表示,可视化地展示了所记录的控制流,帮助快速、直观的查看与理解所记录的控制流。右侧上方面板为代码查看器,展示了运行记录查看器中所选中的操作记录所对应的Web应用前端原HTML或JavaScript文件中的代码位置,帮助快速、方便地定位到所感兴趣的控制流所对应的JavaScript代码位置并提取其中的JavaScript业务逻辑与数据处理逻辑。右侧下方面板为数据查看器,展示了与运行记录查看器中所选中的操作或事件记录相关的数据,有助于方便地对所记录的数据流与原JavaScript代码中的数据处理逻辑进行理解。
通过在Web界面中进行基于动态数据依赖图与基于数据搜索两种方式的数据流分析,可梳理出获取所需数据或实现所需功能需要执行的网络请求以及JavaScript业务逻辑与数据处理逻辑,以及业务逻辑与数据处理逻辑之间的串联关系。
1.3.2.基于动态数据依赖图的数据流分析
根据运行记录日志中所记录的JavaScript操作与事件之间的动态数据依赖关系,构建动态数据依赖图,用双向边联结每对存在直接数据依赖关系或只经过被前述两种过滤机制所过滤的操作的间接依赖关系的操作或事件。有了动态数据依赖图,就可以从一个节点出发进行遍历,计算出该节点的前向或后向可达集合,即该节点所对应的操作或事件存在直接或间接数据依赖的,或者对该操作或事件存在直接或间接数据依赖的所有操作或事件的集合。
本发明方法分析的粒度是JavaScript中的基本操作而不是代码语句,一个语句可能对应多个基本操作,因此本发明方法的分析结果可以映射到以语句为粒度的分析结果,是以语句为粒度的分析结果的超集。这点便于从一些复杂的语句中,只提取与所关注的数据流相关的操作,而除去与之无关的操作。
1.3.3.基于数据搜索的数据流分析
在Web应用前端JavaScript中的数据流经过DOM与UI事件等复杂的浏览器机制的情况下,仅靠基于动态数据依赖图的数据流分析无法分析出完整的数据流。为此,控制流与数据流可视化与分析工具还提供了另外一种数据流分析方式作为其补充,即基于数据搜索的数据流分析。Web应用前端运行时分析程序会记录JavaScript操作以及UI与网络事件的相关数据,表1列出了对于每种操作或事件类型分析程序所记录的相关数据。除了可以在工具Web界面中的数据查看器中查看这些数据以外,还可以在这些数据中搜索所感兴趣的数据,以分析该数据在Web应用前端运行过程中的传播轨迹,包括经过DOM与UI事件等浏览器机制的情况。
2.Web服务运行时环境的设计
基于JavaScript运行时环境Node.js以及HTML与DOM标准的JavaScript实现,能够实现支持JavaScript运行以及HTML与DOM API的Web服务运行时环境,使得从Web应用前端提取的JavaScript业务逻辑与数据处理逻辑能够在服务器端正确运行。
2.1.Web应用前端JavaScript业务逻辑与数据处理逻辑提取与重构方案
本发明的Web服务运行时环境提供了支持HTML与DOM API的JavaScript运行时环境。对于获取所需数据或实现所需功能需要执行的JavaScript业务逻辑与数据处理逻辑全部位于一个不依赖外部变量的函数中时,可以从Web应用前端原HTML或JavaScript文件中,直接提取该函数并进行重构。
对于更通用的情况,为了最小化提取与重构Web应用前端JavaScript业务逻辑与数据处理逻辑的难度与工作量,对所需JavaScript业务逻辑与数据处理逻辑进行重构时,完整保留原HTML或JavaScript文件以作为基础,定位到所需JavaScript业务逻辑与数据处理逻辑的入口与出口,并对入口与出口进行重构,使得构造的Web服务处理程序能够顺利地调用该JavaScript业务逻辑与数据处理逻辑并获取结果,为此需要结合Web应用前端控制流与数据流分析工具进行分析,其具体流程如下:
第1步:定位所需JavaScript业务逻辑与数据处理逻辑的入口或出口。
定位所需JavaScript业务逻辑与数据处理逻辑的入口或出口的一种方式是从已知的数据入手,通过Web应用前端控制流与数据流分析工具所提供的基于数据搜索的数据流分析功能,定位该数据在Web应用前端JavaScript的控制流中第一次出现的位置。对于已知来源的值,所定位到的是其第一次使用的位置,适合用于定位JavaScript业务逻辑与数据处理逻辑的入口。对于未知来源的值,所定位到的是其第一次产生的位置,适合用于定位JavaScript业务逻辑与数据处理逻辑的出口。另一种方式是从UI或网络事件入手,在Web应用前端控制流与数据流分析工具Web界面中的运行时查看器中向前或向后跟踪控制流,找到所需JavaScript业务逻辑与数据处理逻辑的入口或出口。
第2步:定位所需JavaScript业务逻辑与数据处理逻辑的出口或入口。
其实第1步与第2步可以合为1个步骤说明,即分别定位所需JavaScript业务逻辑与数据处理逻辑的入口和出口。若在第1步中定位到所需JavaScript业务逻辑与数据处理逻辑的入口,则第2步中需要定位所需JavaScript业务逻辑与数据处理逻辑的出口,若在第1步中定位到所需JavaScript业务逻辑与数据处理逻辑的出口,则第2步需要定位所需JavaScript业务逻辑与数据处理逻辑的入口。第2步既可以使用第1步中所介绍的方法,也可以通过Web应用前端控制流与数据流分析工具所提供的基于动态数据依赖图的数据流分析功能,从第1步中所定位到的JavaScript业务逻辑与数据处理逻辑的入口或出口出发,进行前向或后向数据流分析,以定位其出口或入口。若由于数据流经过DOM与UI事件等浏览器机制,只通过基于动态数据依赖图的数据流分析无法分析出完整的数据流,则还可以在数据流经过浏览器机制的位置,使用基于数据搜索的数据流分析功能作为补充。
第3步:对所需JavaScript业务逻辑与数据处理逻辑的入口进行重构。
定位到所需JavaScript业务逻辑与数据处理逻辑的入口之后,复制该处函数调用栈上适合的函数并进行以下重构:首先,若该JavaScript业务逻辑与数据处理逻辑的输入数据不是原函数的参数,例如是从DOM节点中读取的,则在所复制函数中需要将其修改为函数参数,以便从Web服务处理程序接受数据。其次,需要移除所复制函数的其他参数,在其函数体开头处声明同名变量并赋值为所需的值,针对获取所需数据或实现所需功能的特定场景,这些参数值经常为常量,或可以从Web应用前端JavaScript业务逻辑与数据处理逻辑中的其他位置获取。另外,若原函数包含太多与获取所需数据或实现所需功能无关的逻辑,则在所复制函数中可以选择将其移除。最后,需要将所复制函数保存到JavaScript的全局作用域,以便从Web服务处理程序中调用,这可以通过将其写入windows对象的一个属性实现。
第4步:对所需JavaScript业务逻辑与数据处理逻辑的出口进行重构。
在所需JavaScript业务逻辑与数据处理逻辑的出口处,得到所需结果值后,需要分为两种情况进行重构。对于该JavaScript业务逻辑与数据处理逻辑的入口与出口在JavaScript中单一同步控制流中的情况,在第3步中应该在入口处函数调用栈上选择最近的同时包含入口与出口的函数进行复制。若原函数的返回值为所需结果值,则无需对所复制函数的返回值进行修改。然而,JavaScript业务逻辑与数据处理逻辑的结果值经常会被直接写入DOM节点中或作为Ajax请求的参数发送请求,因此需要对所复制函数进行重构,将所需结果值作为其返回值返回,以便Web服务处程序获取所需结果值。对于该JavaScript业务逻辑与数据处理逻辑的入口与出口在JavaScript中两个异步控制流中的情况,需要对出口处进行重构,以所需结果值为参数调用Web服务运行时环境所提供的回调方法,将所需结果值异步地传递给Web服务处理程序。
2.2.Web服务运行时环境架构
Web服务运行时环境(Web Service Runtime)的框架如图4所示。Web服务运行时环境的底层基于JavaScript运行时环境Node.js,从而天然支持了JavaScript的运行,同时其支持高并发IO的优势也很适合于实现Web服务运行时环境的场景。在Node.js的基础上,Web服务运行时环境提供了HTTP服务器模块(HTTP Server),供上层构造的Web服务处理程序(Web Services)使用以接受Web服务的消费者所发来的HTTP请求。Web服务运行时环境还提供了支持HTML与DOM API的JavaScript运行时环境(HTML-and-DOM-capable JS Runtime),使得所提取与重构的JavaScript业务逻辑与数据处理逻辑,在其中穿插着大量对浏览器所提供的API的调用的情况下,能够在服务器端正确运行。该JavaScript运行时环境的基础是轻量级的HTML与DOM标准的JavaScript实现,该库模拟了浏览器功能的子集,然而避免了浏览器内核所进行的布局、渲染等一系列操作的巨大开销,从而保证了Web服务具有良好的性能、延迟与可扩展性。
该JavaScript运行时环境对上述轻量级的HTML与DOM标准的JavaScript实现进行了封装,并提供API供上层构造的Web服务处理程序调用。对于需要在JavaScript运行时环境中加载所需服务化的Web应用前端的原HTML文件的情况,该HTML文件中可能会通过HTML标签加载JavaScript、CSS、图片等各类资源,另外所提取的原JavaScript文件中也可能通过Ajax请求加载各类资源。对于其中的CSS、图片等与执行所提取与重构的JavaScript业务逻辑与数据处理逻辑无关的资源,JavaScript运行时环境会直接将其忽略,以避免影响性能。而对于JavaScript、JSON数据等相关资源,JavaScript运行时环境提供了资源缓存(Resource Cache)模块,会根据请求的HTTP方法、URL、Query String参数、请求体等数据的MD5摘要对资源进行缓存,当后续资源请求的MD5摘要匹配时将直接从本地缓存中加载资源,提高了JavaScript业务逻辑与数据处理逻辑的执行性能。
最后,有些情况下获取所需数据或实现所需功能需要执行在多个不同页面中的JavaScript业务逻辑与数据处理逻辑。例如,从一个需要登录的Web应用中获取一个数据,可能需要先执行登录页面中的一段JavaScript业务逻辑与数据处理逻辑对用户名与密码进行加密,再请求登录API获取Cookie,再带着Cookie请求获取数据的API,最后执行登陆后的页面中的一段JavaScript业务逻辑与数据处理逻辑对所获取的详情数据进行解码,才能得到最终所需的数据。如果执行多个不同页面中的JavaScript业务逻辑与数据处理逻辑,需要加载多个不同的HTML文件,则需要在页面跳转时传递上述轻量级的HTML与DOM标准的JavaScript实现中的Cookie等数据。由于现阶段上述轻量级的HTML与DOM标准的JavaScript实现不支持页面跳转,因此JavaScript运行时环境还提供了导航管理模块(Navigation Manager)以处理页面跳转时Cookie等数据的传递。
2.3.Web服务处理程序的构造
服务化的最后一步是,在已经分析与理解了所需服务化的Web应用前端的控制流与数据流,并梳理出了获取所需数据或实现所需功能需要执行的网络请求以及JavaScript业务逻辑与数据处理逻辑以及业务逻辑与数据处理逻辑之间的串联关系,之后对所需JavaScript业务逻辑与数据处理逻辑进行了提取与重构的基础上,构造Web服务处理程序,主要需要完成以下三点:
1).调用Web服务运行时环境所提供的HTTP服务器模块,注册所需要监听的URL路径与HTTP方法,以接受Web服务的消费者所发来的HTTP请求。
2).根据所梳理出的原Web应用前端的逻辑顺序,执行获取所需数据或实现所需功能需要执行的网络请求,以及通过Web服务运行时环境所提供的支持HTML与DOM API的JavaScritp运行时环境来执行所提取的JavaScript业务逻辑与数据处理逻辑,并将它们串联。
3).得到最终结果后,将其整理为所需格式并作为Web服务的最终响应返回给Web服务的消费者。
对于Web应用前端运行时分析工具中运行时信息与分析结果采集工具的实现,运行时信息与分析结果采集工具分为前端与后端。前端最重要的部分是通过插桩方式插入所需服务化的Web应用前端HTML与JavaScript文件中的Web应用前端运行时分析程序。该分析程序采用JavaScript语言构造并基于所述Web应用插装模块实现,包括traceAndAnalyze.js、filter.js、utils.js、traceLogger.js几个文件。traceAndAnalyze.js文件实现了所述Web应用插装模块的运行时环境所提供的以下回调函数:invokeFunPre、invokeFun、literal、forinObject、declare、getFieldPre、getField、putFieldPre、putField、read、write、_return、functionEnter、functionExit、scriptEnter、scriptExit、binaryPre、binary、unaryPre、unary、conditional。通过实现以上回调函数以及包装并替换浏览器原生的XMLHttpRequest对象的方法实现Ajax请求事件的捕捉,实现了两个主要功能:一是以日志的方式记录Web应用前端的控制流信息、UI与网络事件以及相关的数据,二是分析运行记录日志中所记录的JavaScript操作与事件之间的动态数据依赖关系。filter.js实现了基于URL与基于数据搜索两种运行记录过滤机制。utils.js实现了安全的JavaScript值的序列化算法。traceLogger.js实现了基于WebSocket协议的日志与分析结果传输。
在分析程序中记录操作与事件的相关数据时,首先需要将JavaScript中的值序列化为字符串。对于JavaScript中的值,常规的序列化方式是使用浏览器原生的JSON.stringify函数,然而分析程序需要记录的数据中很多都是包含循环引用的JavaScript对象。对于这类包含循环引用的JavaScript对象,JSON.stringify函数会报错且无法完成序列化。因此,分析程序实现了安全的JavaScript值的序列化算法,当需要序列化的值是JavaScript对象时,算法会在对其进行遍历并序列化的过程中检查每一个属性是否指向其祖先对象,若是则用该祖先对象的路径来作为该属性的序列化结果,避免了死循环的发生。
另外,JSON.stringify方法对undefined进行序列化的结果还是undefined而不是字符串,导致日志中记录的数据是空字符串,无法与真正的空字符串进行区分,因此分析程序中的序列化算法还会对undefined进行特殊处理。还有,为了减少记录与传输的数据量以及提高插桩后的Web应用的运行性能,序列化算法还会对浏览器环境JavaScript中经常出现的大对象进行特殊处理,例如window对象与document对象。由于函数的函数体在SourceMaps中已经存在,而事件对象中所需的相关数据以及单独作为日志的字段来记录,都不需要重复记录,因此为了同样的目的,序列化算法还会对Function类型与Event类型的对象进行特殊处理。不论是需要序列化的数据本身为这些值或这些值出现在需要序列化的数据的某一层属性中,都会进行特殊处理。
分析程序采集到的运行记录日志将以JSON格式传输到后端的运行时信息与分析结果采集服务器并写入数据库。即使有了基于URL的过滤机制,由于需要记录如函数调用参数与返回值、变量读写的值、运算操作的操作数与结果等大量数据,如果将日志全部保存在所分析页面的JavaScript内存中,会导致内存占用过高,甚至导致页面奔溃。因此为了减少页面的内存占用,本文选择将捕捉到的运行记录日志实时地用WebSocket协议传输到后端的运行时信息与分析结果采集服务器。分析程序中维护了一个待发日志的队列,并通过Ping/Pong方式保证采集服务器收到日志,即每次发送一条日志,当采集服务器收到后发送确认消息给分析程序,并将日志写入数据库,当分析程序收到确认消息后即可释放该条日志所占用的内存,并发送下一条日志,如此重复直至日志队列为空。
后端的运行时信息与分析结果采集服务器采用JavaScript语言构造并基于JavaScript运行时环境Node.js实现。其中的WebSocket服务器采用了轻量级的WebSocket与HTTP服务器实现uWebSockets,运行记录日志采用了基于文件的轻量级JavaScript数据库来存储。
对于Web应用前端运行时分析工具中控制流与数据流可视化与分析工具的实现,控制流与数据流可视化与分析工具基于Web实现,分为前端与后端。后端服务器同样采用JavaScript语言构造并基于Node.js实现。服务器采用轻量级的Web应用框架来向浏览器提供前端Web界面的静态资源,以及向Web界面提供从日志数据库读取的运行记录日志、从文件中读取的Source Maps与动态数据依赖关系的分析结果。
前端Web界面基于Web技术实现,由单个HTML页面以及JavaScript与CSS代码构成。
对于Web服务运行时环境的实现,Web服务运行时环境的底层基于JavaScript运行时环境Node.js。运行时环境启动时将会初始化HTTP服务器模块以及JavaScript运行时环境,之后读取services目录下的所有Web服务处理程序并对其进行初始化,最后启动HTTP服务器开始监听Web服务的消费者所发来的HTTP请求。
其中的HTTP服务器模块采用了轻量级的Web应用框架来实现,使得开发者能够在Web服务程序中方便地注册所需监听的URL路径与HTTP方法,以接受Web服务的消费者所发来的HTTP请求,并方便地获取请求头、URL路径、Query String参数、请求体等信息。
支持HTML与DOM API的JavaScript运行时环境基于轻量级的HTML与DOM标准的JavaScript实现来实现。该JavaScript运行时环境对上述轻量级的HTML与DOM标准的JavaScript实现进行了封装,并提供API供上层的开发者所构造的Web服务处理程序调用。JavaScript运行时环境对上述轻量级的HTML与DOM标准的JavaScript实现进行了配置,使其忽略加载CSS、图片等与执行所提取与重构的JavaScript逻辑无关的资源。而对于JavaScript、JSON数据等相关资源,JavaScript运行时环境通过上述轻量级的HTML与DOM标准的JavaScript实现的resourceLoader选项实现了资源缓存模块,提供了一个自定义的资源加载器,会根据请求的HTTP方法、URL、Query String参数、请求体等数据计算MD5摘要作为文件名,将资源缓存在本地文件中,当后续资源请求的MD5摘要匹配时将直接从本地缓存中加载资源。
由于现阶段上述轻量级的HTML与DOM标准的JavaScript实现不支持页面跳转,为了在页面跳转时传递上述轻量级的HTML与DOM标准的JavaScript实现中的Cookie等数据,JavaScript运行时环境还实现了导航管理模块,在上述轻量级的HTML与DOM标准的JavaScript实现中加载新页面之前读取其中上一个页面的Cookie等数据,并在加载新页面时复用。
如,下述为Web服务处理程序的部分实现示例::
上述实施例仅为优选实施例,并不用以限制本发明的保护范围,在本发明的精神和原则之内所作的任何修改、等同替换和改进等,均应包含在本发明的保护范围之内。