转载

使用 Node.js 在 IBM i 上开发原生 JavaScript 应用程序

简介

Node.js 是一个基于 Google Chrome V8 JavaScript Engine 的开源项目。它为未使用浏览器运行的服务器端 JavaScript 应用程序提供了一个平台。 事件驱动 、 非阻塞 I/O 模型使它既是轻量化的,又能高效使用。它还提供了一些内置模块来简化编程,尤其是网络应用程序。还有许多第三方模块也可以使用内置的 npm(node packaged modules,Node 封装模块)工具来轻松地安装,以便扩展 Node.js。

备注:Node.js 是 Joyent 的官方商标。

现在支持在 IBM i 平台上使用 Node.js。为了在 IBM i 上应用开源技术,还创建了 IBM i Open Source Solutions 授权程序产品 (LPO) 5733OPS。它包含在 IBM i 操作系统的 Bonus Pack 中。在安装之后,这个免费的 LPO 通过 IBM® HTTP Server for i Group PTF 进行维护。

图 1. Node.js 将 JavaScript 代码转码为机器代码

使用 Node.js 在 IBM i 上开发原生 JavaScript 应用程序

除了其核心功能之外,IBM i 上的 Node.js 还提供了以下两个 IBM i 独有的扩展:

  • IBM DB2® for i 访问库 ,其中包含可调用来与 DB2 for i 数据库对象交互的 JavaScript 服务。
  • Node.js toolkit for IBM i ,允许用户通过 XMLSERVICE 访问 IBM i 系统资源,比如系统状态、系统值、作业信息、用户空间、数据队列、对象信息,等等。

图 2. Node.js for IBM i 基础架构

使用 Node.js 在 IBM i 上开发原生 JavaScript 应用程序

本文将介绍 Node.js 的基本知识,还将介绍如何开始在 IBM i 上使用它。文中将指导您在 IBM i 上设置 Node.js,使用一些示例来指导您逐步完成该过程。

回页首

必备软件

Node.js for IBM i 打包在 5733OPS 中,后者仅支持 IBM i 7.1 及更高版本。Node.js 是在这个新 LPO 的选项 1 中提供的。除了安装新 LPO 之外,还需要安装其他一些软件程序才能在 IBM i 上使用 Node.js。

  • 所需的已授权程序:
    • 5733OPS,选项 1-IBM i Open Source Solutions
    • 5770SS1,选项 33-Portable App Solutions Environment
    • 5733SC1,选项 1-OpenSSH, OpenSSL、zlib
    • 5770DG1,*BASE – IBM HTTP Server for i
  • 如果需要将 Node.js 扩展到已安装功能之外,还需要一些可选软件。
    • npm 需要 Python 来安装第三方附件。
    • 如果希望通过 npm 安装基于 C/C++ 的第三方附件,则需要 GCC。
    • 如果希望通过 npm 安装使用 Github 作为源代码存储库的第三方附件,则需要 Git

对于 Python 和 PASE 中的其他开源库安装,请参阅 开源二进制程序 在线手册和文档。

回页首

将 Node.js 安装在 IBM i 上

从物理 DVD 介质或镜像文件安装 5733OPS 选项 1 产品。然后应用最新的 IBM HTTP Server for i PTF Group 来获得最新的 Node.js 支持:

  • IBM i 7.1 PTF Group SF99368 – 31 级(或更高级别)
  • IBM i 7.2 PTF Group SF99713 – 5 级(或更高级别)

成功安装所有软件后,将创建 /QOpenSys/QIBM/ProdData/Node/ 目录。

准备好软件环境后,执行以下步骤来验证安装:

  1. 使用下面这条 CL 命令启动一个 Qshell 会话。
QSH

或者使用下面这条 CL 命令启动 PASE 会话。

CALL QP2TERM
  1. 运行以下命令来验证 Node.js 运行时版本级别。这两条命令位于 /QOpenSys/QIBM/ProdData/Node/bin 中,可全局调用。
node –v

输出必须是系统上的有效的 Node.js 版本,比如 v0.10.29。

npm –v

输出必须是系统上有效的 npm 版本,比如 1.4.14。

图 3. Node.js for IBM i 安装验证

使用 Node.js 在 IBM i 上开发原生 JavaScript 应用程序

如果版本信息看起来有效,则安装已成功。

备注:在 Qshell 会话中,一些 Node.js 应用程序可能抛出 signal 5 错误。此错误是 Qshell 的线程限制所导致的。请参阅IBM 知识中心文档,了解有关的更多细节。

要删除此限制,可以添加环境变量 QIBM_MULTI_THREADED 和值 Y ,然后重新启动 Qshell 会话。或者可以对您的应用程序使用 PASE 会话。

下面这条 CL 命令启动了一个支持多线程的 Qshell 进程。

ADDENVVAR ENVVAR(QIBM_MULTI_THREADED) VALUE(Y)

图 4. 为 Qshell 启用多线程功能

使用 Node.js 在 IBM i 上开发原生 JavaScript 应用程序

回页首

示例概述

前几节介绍了如何在 IBM i 上设置 Node.js 运行时。在剩余几节中,我们将通过一个编程示例来展示 Node.js for i 的功能。这个示例将创建一个 Web 服务器,允许用户查询 DB2 for i 数据库,并使用 Web 浏览器运行 CL 命令。

备注:Node.js 不支持使用 EBCDIC 编码的源文件。可使用 UTF-8 编码或兼容 UTF-8 的 CCSID,比如 819 (ISO 8859-1 ASCII)。

回页首

使用 Node.js 创建一个 Web 应用程序

IBM i 支持所有 Node.js 核心功能。一个核心功能是使用 IBM i 的 Node.js 支持轻松地创建 Web 服务器。

  1. 在任何集成的文件系统目录(例如 /home/njs/sample.js)中创建一个名为 sample.js 的包含以下内容的文件。下面的代码创建了 Web 服务器并提供了一个简单的 “Hello World” 网站。在下面的示例代码中,将 IP_Address 替换为您服务器的实际 IP 地址,将 Port 替换为服务器要用于监听的端口号。
var http = require('http'); var ip = "IP_Address"; var port = Port; var webserver = http.createServer(function (req, res) {          res.writeHead(200, {'Content-Type': 'text/plain'});         res.end('Hello World/n'); }); webserver.listen(port, ip); console.log('Server running at http://' + ip + ':' + port);
  1. 在创建并自定义该文件后,运行 JavaScript 程序来启动 Web 服务器。
node /home/njs/sample.js

如果显示下面这条消息,您就会知道 Web 服务器在成功运行。

Server running at http:// IP_address : port /

现在您可以打开浏览器访问 Node.js 启动的 Web 服务器。此时将会显示 “Hello World” 网站,如下图所示。

图 5. 验证 Web 服务器

使用 Node.js 在 IBM i 上开发原生 JavaScript 应用程序
  1. 终止 Web 服务器。

在本例中,Web 服务器监听端口 8081 来接受请求并响应。要终止这个 Web 服务器,需要手动终止该作业。要结终止 Web 服务器作业,可在 QSH 会话中按 Esc 键,选择选项 2 来处理当前作业。接下来,终止运行 node 程序的选项为 4 的作业,如图 6 所示。

图 6. 手动终止 Node.js 作业

使用 Node.js 在 IBM i 上开发原生 JavaScript 应用程序

要自动化 Node.js Web 服务器的管理,可创建自定义的 CL 命令来执行这些操作。可在文章 在 IBM i 上加速运行 Tomcat 服务器 的 “第 9 步 - 创建自定义 CL 命令来启动 Tomcat 服务器” 中找到创建自定义 CL 命令的更多信息。

  1. 提供静态网页。

在前面的 JavaScript 代码中,Web 服务器仅使用 “Hello World” 响应所有请求。现在,我们将扩展 sample.js 程序,以便在浏览器请求 URL http://<hostname>:port/sample.html 时,从一个静态文件读取内容并响应客户端。

要使用静态网页来响应客户端,Node.js 需要使用 “fs” 文件系统模块和 “url” 模块来解析请求字符串。您需要更新 sample.js 文件,使之包含这些额外的模块。请记住更新 IP 地址和端口值。可以使用您的值更新下面这个 sample.js 文件:

var http = require('http'); var fs = require('fs'); var url = require('url');  var ip = "IP_Address"; var port = Port; var webserver = http.createServer(function (req, res) {    var realPath = __dirname + url.parse(req.url).pathname;   fs.exists(realPath, function(exists){     if(!exists){       res.writeHead(404, {'Content-Type': 'text/plain'});        res.end("404 Not Found");      } else {       var file = fs.createReadStream(realPath);       res.writeHead(200, {'Content-Type': 'text/html'});       file.on('data', res.write.bind(res));       file.on('close', res.end.bind(res));        file.on('error', function(err){        res.writeHead(500, {'Content-Type': 'text/plain'});        res.end("500 Internal Server Error");       });      }  }); }); webserver.listen(port, ip);  console.log('Server running at http://' + ip + ':' + port);

备注:__dirname 是一个 Node.js 内部变量,用于获取当前运行的脚本所在的目录名称。

然后,创建一个名为 sample.html 且包含以下内容的静态 HTML 文件,将它上传到 sample.js 文件所在的相同目录。

<!DOCTYPE HTML>  <html lang="en-US">  <head>    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />   <title>Node.js for i Sample</title>  </head>  <style>  input {  height:30px;  border:#ccc solid 1px  } input[type="text"] {  width:500px  } input[type="submit"] {  margin:1em;   width:120px  }  </style> <body>   <form name="input" action="query" method="get">   <div>SQL Command </div>   <input type="text" name="sql" placeholder="SELECT * FROM ..."/>   <input type="submit" value="Query"/>  </form>   <form name="input" action="cmd" method="get">   <div>CL Command </div>   <input type="text" name="cl" placeholder="WRKSYSSTS"/>   <input type="submit" value="Run"/>  </form>  </body> </html>
  1. 重新运行 sample.js 文件。

首先,结束正在运行的服务器,然后像第 2 步描述的那样重新启动该 Web 服务器。现在我们可以启动浏览器来访问示例页面 http://ip:port/sample.html

图 7. 提供静态网页

使用 Node.js 在 IBM i 上开发原生 JavaScript 应用程序

尽管目前它只提供了一个静态页面,但是,一个非常简单的 Web 应用程序框架已经准备好了。您可以看到开始使用它有多简单。不需要额外的应用服务器设置,也不需要特殊的部署步骤。在下面几节中,将使用更多 JavaScript 代码来扩充示例,以完成一些有意义的功能,运行 SQL 语句和 CL 命令。

回页首

访问 DB2 for i 数据

在本节中,可以扩充示例来使用 DB2 for i 访问库 API 访问 DB2 for i 数据。该 Web 应用程序允许您在网页上运行任何 SQL 语句并显示结果。

警告:下面的示例演示了通过 Node.js 访问数据的功能。实际上,您不希望将命令或 SQL 接口向外暴漏给某个用户。Node.js 服务器在启动 Web 服务器的用户的授权下运行。

DB2 for i Extension 是一个 JavaScript API 集合,用于在 IBM i 上执行 DB2 数据库操作。它提供了与 DB2 for i SQL 调用级接口 (CLI) 对应的 JavaScript 接口。所有 DB2 CLI API 都已在该扩展中公开。Node.js for IBM i 随带了访问库,它位于: /QOpenSys/QIBM/ProdData/Node/os400/db2i/

要支持使用 DB2 for i API,您的源代码中只需包含 db2.js 文件。

var db = require('/QOpenSys/QIBM/ProdData/Node/os400/db2i/lib/db2');

要连接到数据库,需要设置该数据库的名称或别名。可发出 CL 命令 WRKRDBDIRE 来获取目标数据库的名称。在图 9 中所示的示例中,本地数据库名为 G0488C55 。如果需要连接到本地数据库,可在 db.conn() API 上使用特殊值 ‘*LOCAL’。

图 8. 找到本地数据库名称

使用 Node.js 在 IBM i 上开发原生 JavaScript 应用程序

除了 CL 命令之外,数据库名称也可由 SQL 确定。您可以发出 CL 命令 STRSQL 来启动 SQL 交互式会话,运行以下 SQL。

SELECT CATALOG_NAME, CATALOG_STATUS, CATALOG_TYPE FROM QSYS2.SYSCATALOGS

请参考以下输出。

CATALOG_NAME CATALOG_STATUS CATALOG_TYPE
G0488C55 AVAILABLE LOCAL
IASP1 VARYOFF LOCAL
LP21UT24 UNKNOWN REMOTE

现在让我们扩展 sample.js 文件,从请求查询字符串读取 SQL 语句,运行该 SQL 语句,然后将结果集返回给浏览器。

var http = require('http'); var fs = require('fs');  var url = require('url');  var db = require('/QOpenSys/QIBM/ProdData/Node/os400/db2i/lib/db2');  var DBname = "*LOCAL";  var ip = "IP_Address ";  var port =Port ;         var webserver = http.createServer(function (req, res) {   var realPath = __dirname + url.parse(req.url).pathname;   fs.exists(realPath, function(exists){    if(!exists){       var sql = url.parse(req.url, true).query.sql;      res.writeHead(200, {'Content-Type': 'text/plain'});       if(sql && sql.length > 0) {        db.init();        db.conn(DBname);  // Connect to the DB        db.exec(sql, function(rs) {   // Query the statement         res.write(JSON.stringify(rs));        });        db.close();       }       res.end();    } else {     var file = fs.createReadStream(realPath);     res.writeHead(200, {'Content-Type':'text/html'});     file.on('data', res.write.bind(res));     file.on('close', res.end.bind(res));      file.on('error', function(err){      res.writeHead(500, {'Content-Type':'text/plain'});      res.end("500 Internal Server Error");     });    }    });  });  webserver.listen(port, ip);  console.log('Server running at http://' + ip + ':' + port);

有两种数据库连接模式 - 服务器模式和非服务器模式。默认情况下,使用的是非服务器模式。

在 db.conn() 上使用 *LOCAL 数据库时,非服务器模式不需要或不用验证用户 ID 和密码。相反,它会使用 *CURUSR 值来处理连接,这对应于启动 node 服务器的用户。这正是前面的示例不包含任何用户个人信息的原因。

使用服务器模式,使用一个特定的用户个人信息连接到 *LOCAL 数据库。对于服务器模式,需要输入用户 ID 和密码并验证。但是,如果用户 ID 或密码设置为 NULL,连接将使用对当前运行 Node.js 程序的作业有效的用户 ID。

如果程序需要连接到一个远程数据库或一个独立 ASP (iASP),那么服务器模式和非服务器模式都需要有效的用户 ID 和密码。

您可以在初始化函数的回调函数中启用服务器模式,如下所示。

db.init(function(){      db.serverMode(true); //Enable Server Mode if needed });

在更新源代码时,结束 Node.js 程序并重新启动 Web 服务器,像前几节中介绍的那样。

接下来,将下面这个 URL 输入到浏览器中:http://ip:port/sample.html。上面添加的代码会让 SQL 函数发挥作用。在第一个字段中输入任何 SQL 语句并单击 Query 。Node.js 服务器对指定的数据库运行 SQL 语句。例如,下面这条 SQL 语句将会查找最近 7 天内增长到最大大小的文件:

select SYS_NAME, SYS_ONAME, CURRENT_VALUE from qsys2.syslimits where sizing_name =   'MAXIMUM NUMBER OF VALID ROWS' AND lastchg > current timestamp - 7 days   order by current_value desc

图 9. 从 DB2 数据库查询数据

使用 Node.js 在 IBM i 上开发原生 JavaScript 应用程序

输出的结果集为 JSON 格式。您可以使用 JSON.stringify() 函数将它转换为容易阅读的文本,或者直接访问键值对。

图 10. SQL 查询的结果

使用 Node.js 在 IBM i 上开发原生 JavaScript 应用程序

回页首

访问 IBM i 原生对象

Node.js Toolkit for IBM i API 集基于 XMLSERVICE 来轻松地访问 IBM i 原生对象,比如 PTF 信息、数据队列和程序。目前 Node.js Toolkit for IBM i 提供了以下类。

  • itoolkit – 调用 CL 命令、QSHELL 命令、程序、服务程序中的过程和 SQL 语句的基本函数和接口。
  • iwork – 获取系统信息和作业状态的接口。
  • iprod – 获取产品和 PTF 信息的接口。
  • iuserSpace – 操作用户空间的接口。
  • inetwork – 获取网络信息的接口。
  • iobj – 获取对象授权,以及命令、程序、服务程序的信息的接口。
  • idataq – 操作数据队列的接口。

Node.js for IBM i 随带了 Node.js Toolkit for IBM i,它位于 /QOpenSys/QIBM/ProdData/Node/os400/os400/ 目录中。要使用 Node.js Toolkit for IBM i,首先需要 itoolkit.js 文件。itoolkit.js 文件将 XMLSERVICE 支持与 Node.js 联系起来,它是其他所有 Node.js Toolkit 函数的基础。

var xt = require('/QOpenSys/QIBM/ProdData/Node/os400/xstoolkit/lib/itoolkit');

现在让我们继续修改 sample.js,使用 itoolkit 类来运行 CL 命令。

var http = require('http');  var fs = require('fs');  var url = require('url');  var db = require('/QOpenSys/QIBM/ProdData/Node/os400/db2i/lib/db2'); var xt = require('/QOpenSys/QIBM/ProdData/Node/os400/xstoolkit/lib/itoolkit');   var DBname = "*LOCAL ";  var ip = "IP_Address";  var port = Port;       var webserver = http.createServer(function (req, res) {   var realPath = __dirname + url.parse(req.url).pathname;  fs.exists(realPath,function(exists){   if(!exists){    var sql = url.parse(req.url, true).query.sql;        var cl = url.parse(req.url, true).query.cl;    res.writeHead(200, {'Content-Type': 'text/plain'});     if(sql && sql.length > 0) {     console.log("SQL statement : " + sql);     db.init();     db.conn(DBname);     db.exec(sql, function(rs) {      res.write(JSON.stringify(rs));      });     db.close();    }         if(cl && cl.length > 0)        {         console.log("CL statement : " + cl);          var conn = new xt.iConn(DBname);         conn.add(xt.iSh("system -i " + cl));          function cb(str) {         res.write(xt.xmlToJson(str)[0].data);         }          conn.run(cb);         }     res.end();   } else {     var file = fs.createReadStream(realPath);    res.writeHead(200, {'Content-Type': 'text/html'});     file.on('data', res.write.bind(res));     file.on('close', res.end.bind(res));    file.on('error', function(err){      res.writeHead(500, {'Content-Type': 'text/plain'});      res.end("500 Internal Server Error");     });    }  }); }); webserver.listen(port, ip); console.log('Server running at http://' + ip + ':' + port);

Node.js Toolkit for IBM i 允许批量运行多个命令。在本例中,我们只需获取第一个结果。

现在在您的浏览器会话中刷新 http://ip:port/sample.html 页面。在第二个字段中输入一条 CL 命令并单击 Run 。Node.js Toolkit for IBM i 将会运行该命令并将结果返回给浏览器。在本例中,运行了 Display System Status (DSPSYSSTS) 命令来获取当前系统状态。

图 11. 使用 Node.js 运行 DSPSYSSTS 命令

使用 Node.js 在 IBM i 上开发原生 JavaScript 应用程序

下图显示了该 CL 命令的输出。

图 12. DSPSYSSTS 示例输出

使用 Node.js 在 IBM i 上开发原生 JavaScript 应用程序

点击查看大图

关闭 [x]

图 12. DSPSYSSTS 示例输出

使用 Node.js 在 IBM i 上开发原生 JavaScript 应用程序

回页首

结束语

JavaScript 是一种长期被广泛使用的浏览器脚本语言。现在已在服务器端启用 Node.js,这使它对 IBM i 客户端更加有用。除了经典的 JavaScript API 之外,Node.js 还提供了多个内置的模块来轻松构建现代应用程序。请参阅 Node.js v0.12.0 手册和文档 ,解这些内置 API 的更多细节。DB2 访问库和 Node.js Toolkit for IBM i 在 IBM i 上进一步扩展了 Node.js 的功能。此外,您可以使用 npm 工具安装数千个第三方模块。祝您在 IBM i 上使用 Node.js 愉快。

回页首

参考资料

正文到此结束
Loading...