nodejs基础教程(3)
关注公众号
获取最新福利
微信公众号

nodejs基础教程(3)

时间: 03/01/2017作者: cll浏览量: 1459

本教程分为三部分:

14. Nodejs工具模块

Node.js工具模块 在 Node.js 模块库中有很多好用的模块。接下来我们为大家介绍几种常用模块的使用:

14.1 OS模块

Node.js os 模块提供了一些基本的系统操作函数。我们可以通过以下方式引入该模块:

var os = require("os")

方法

序号 方法&描述
1 os.tmpdir() 返回操作系统的默认临时文件夹。
2 os.endianness() 返回 CPU 的字节序,可能的是 "BE" 或 "LE"。
3 os.hostname() 返回操作系统的主机名。
4 os.type() 返回操作系统名
5 os.platform() 返回操作系统名
6 os.arch() 返回操作系统 CPU 架构,可能的值有 "x64"、"arm" 和 "ia32"。
7 os.release() 返回操作系统的发行版本。
8 os.uptime() 返回操作系统运行的时间,以秒为单位。
9 os.loadavg() 返回一个包含 1、5、15 分钟平均负载的数组。
10 os.totalmem() 返回系统内存总量,单位为字节。
11 os.freemem() 返回操作系统空闲内存量,单位是字节。
12 os.cpus() 返回一个对象数组,包含所安装的每个 CPU/内核的信息:型号、速度(单位 MHz)、时间(一个包含 user、nice、sys、idle 和 irq 所使用 CPU/内核毫秒数的对象)。
13 os.networkInterfaces() 获得网络接口列表。

属性


序号 属性&描述
1 os.EOL 定义了操作系统的行尾符的常量。

实例 创建 main.js 文件,代码如下所示:

var os = require("os");

// CPU 的字节序
console.log('endianness : ' + os.endianness());

// 操作系统名
console.log('type : ' + os.type());

// 操作系统名
console.log('platform : ' + os.platform());

// 系统内存总量
console.log('total memory : ' + os.totalmem() + " bytes.");

// 操作系统空闲内存量
console.log('free memory : ' + os.freemem() + " bytes.");

代码执行结果如下:

endianness : LE
type : Windows_NT
platform : win32
total memory : 8493617152 bytes.
free memory : 4861128704 bytes.

14.2 Path模块

Node.js path 模块提供了一些用于处理文件路径的小工具,我们可以通过以下方式引入该模块:

var path = require("path")

方法

序号 方法&描述
1 path.normalize(p) 规范化路径,注意'..' 和 '.'。
2 path.join([path1][, path2][, ...]) 用于连接路径。该方法的主要用途在于,会正确使用当前系统的路径分隔符,Unix系统是"/",Windows系统是"\"。
3 path.resolve([from ...], to) 将 to 参数解析为绝对路径。
4 path.isAbsolute(path) 判断参数 path 是否是绝对路径。
5 path.relative(from, to) 用于将相对路径转为绝对路径。
6 path.dirname(p) 返回路径中代表文件夹的部分,同 Unix 的dirname 命令类似。
7 path.basename(p[, ext]) 返回路径中的最后一部分。同 Unix 命令 bashname 类似。
8 path.extname(p) 返回路径中文件的后缀名,即路径中最后一个'.'之后的部分。如果一个路径中并不包含'.'或该路径只包含一个'.' 且这个'.'为路径的第一个字符,则此命令返回空字符串。
9 path.parse(pathString) 返回路径字符串的对象。
10 path.format(pathObject) 从对象中返回路径字符串,和 path.parse 相反。

属性


序号 属性&描述
1 path.sep 平台的文件路径分隔符,'\' 或 '/'。
2 path.delimiter 平台的分隔符, ; or ':'.
3 path.posix 提供上述 path 的方法,不过总是以 posix 兼容的方式交互。
4 path.win32 提供上述 path 的方法,不过总是以 win32 兼容的方式交互。

实例 创建 main.js 文件,代码如下所示:

var path = require("path");

// 格式化路径
console.log('normalization : ' + path.normalize('/test/test1//2slashes/1slash/tab/..'));

// 连接路径
console.log('joint path : ' + path.join('/test', 'test1', '2slashes/1slash', 'tab', '..'));

// 转换为绝对路径
console.log('resolve : ' + path.resolve('main.js'));

// 路径中文件的后缀名
console.log('ext name : ' + path.extname('main.js'));

代码执行结果如下:

$ node main.js 
normalization : /test/test1/2slashes/1slash
joint path : /test/test1/2slashes/1slash
resolve : /web/com/1427176256_27423/main.js
ext name : .js

14.3 Net模块

Node.js Net 模块提供了一些用于底层的网络通信的小工具,包含了创建服务器/客户端的方法,我们可以通过以下方式引入该模块:

var net = require("net")

方法

序号 方法&描述
1 net.createServer([options][, connectionListener]) 创建一个 TCP 服务器。参数 connectionListener 自动给 'connection' 事件创建监听器。
2 net.connect(options[, connectionListener]) 返回一个新的 'net.Socket',并连接到指定的地址和端口。 当 socket 建立的时候,将会触发 'connect' 事件。
3 net.createConnection(options[, connectionListener]) 创建一个到端口 port 和 主机 host的 TCP 连接。 host 默认为 'localhost'。
4 net.connect(port[, host][, connectListener]) 创建一个端口为 port 和主机为 host的 TCP 连接 。host 默认为 'localhost'。参数 connectListener 将会作为监听器添加到 'connect' 事件。返回 'net.Socket'。
5 net.createConnection(port[, host][, connectListener]) 创建一个端口为 port 和主机为 host的 TCP 连接 。host 默认为 'localhost'。参数 connectListener 将会作为监听器添加到 'connect' 事件。返回 'net.Socket'。
6 net.connect(path[, connectListener]) 创建连接到 path 的 unix socket 。参数 connectListener 将会作为监听器添加到 'connect' 事件上。返回 'net.Socket'。
7 net.createConnection(path[, connectListener]) 创建连接到 path 的 unix socket 。参数 connectListener 将会作为监听器添加到 'connect' 事件。返回 'net.Socket'。
8 net.isIP(input) 检测输入的是否为 IP 地址。 IPV4 返回 4, IPV6 返回 6,其他情况返回 0。
9 net.isIPv4(input) 如果输入的地址为 IPV4, 返回 true,否则返回 false。
10 net.isIPv6(input) 如果输入的地址为 IPV6, 返回 true,否则返回 false。。
14.3.1 net.Server

net.Server通常用于创建一个 TCP 或本地服务器。

序号 方法&描述
1 server.listen(port[, host][, backlog][, callback]) 监听指定端口 port 和 主机 host ac连接。 默认情况下 host 接受任何 IPv4 地址(INADDR_ANY)的直接连接。端口 port 为 0 时,则会分配一个随机端口。
2 server.listen(path[, callback]) 通过指定 path 的连接,启动一个本地 socket 服务器。
3 server.listen(handle[, callback]) 通过指定句柄连接。
4 server.listen(options[, callback]) options 的属性:端口 port, 主机 host, 和 backlog, 以及可选参数 callback 函数, 他们在一起调用server.listen(port, [host], [backlog], [callback])。还有,参数 path 可以用来指定 UNIX socket。
5 server.close([callback]) 服务器停止接收新的连接,保持现有连接。这是异步函数,当所有连接结束的时候服务器会关闭,并会触发 'close' 事件。
6 server.address() 操作系统返回绑定的地址,协议族名和服务器端口。
7 server.unref() 如果这是事件系统中唯一一个活动的服务器,调用 unref 将允许程序退出。
8 server.ref() 与 unref 相反,如果这是唯一的服务器,在之前被 unref 了的服务器上调用 ref 将不会让程序退出(默认行为)。如果服务器已经被 ref,则再次调用 ref 并不会产生影响。
9 server.getConnections(callback) 异步获取服务器当前活跃连接的数量。当 socket 发送给子进程后才有效;回调函数有 2 个参数 err 和 count。

事件

序号 事件&描述
1 listening 当服务器调用 server.listen 绑定后会触发。
2 connection 当新连接创建后会被触发。socket 是 net.Socket实例。
3 close 服务器关闭时会触发。注意,如果存在连接,这个事件不会被触发直到所有的连接关闭。
4 error 发生错误时触发。'close' 事件将被下列事件直接调用。
14.3.2 net.Socket

net.Socket 对象是 TCP 或 UNIX Socket 的抽象。net.Socket 实例实现了一个双工流接口。 他们可以在用户创建客户端(使用 connect())时使用, 或者由 Node 创建它们,并通过 connection 服务器事件传递给用户。

事件 net.Socket 事件有:

序号 事件&描述
1 lookup 在解析域名后,但在连接前,触发这个事件。对 UNIX sokcet 不适用。
2 connect 成功建立 socket 连接时触发。
3 data 当接收到数据时触发。
4 end 当 socket 另一端发送 FIN 包时,触发该事件。
5 timeout 当 socket 空闲超时时触发,仅是表明 socket 已经空闲。用户必须手动关闭连接。
6 drain 当写缓存为空得时候触发。可用来控制上传。
7 error 错误发生时触发。
8 close 当 socket 完全关闭时触发。参数 had_error 是布尔值,它表示是否因为传输错误导致 socket 关闭。

属性 net.Socket 提供了很多有用的属性,便于控制 socket 交互:

序号 属性&描述
1 socket.bufferSize 该属性显示了要写入缓冲区的字节数。
2 socket.remoteAddress 远程的 IP 地址字符串,例如:'74.125.127.100' or '2001:4860:a005::68'。
3 socket.remoteFamily 远程IP协议族字符串,比如 'IPv4' or 'IPv6'。
4 socket.remotePort 远程端口,数字表示,例如:80 or 21。
5 socket.localAddress 网络连接绑定的本地接口 远程客户端正在连接的本地 IP 地址,字符串表示。例如,如果你在监听'0.0.0.0'而客户端连接在'192.168.1.1',这个值就会是 '192.168.1.1'。
6 socket.localPort 本地端口地址,数字表示。例如:80 or 21。
7 socket.bytesRead 接收到得字节数。
8 socket.bytesWritten 发送的字节数。

方法

序号 方法&描述
1 new net.Socket([options]) 构造一个新的 socket 对象。
2 socket.connect(port[, host][, connectListener]) 指定端口 port 和 主机 host,创建 socket 连接 。参数 host 默认为 localhost。通常情况不需要使用 net.createConnection 打开 socket。只有你实现了自己的 socket 时才会用到。
3 socket.connect(path[, connectListener]) 打开指定路径的 unix socket。通常情况不需要使用 net.createConnection 打开 socket。只有你实现了自己的 socket 时才会用到。
4 socket.setEncoding([encoding]) 设置编码
5 socket.write(data[, encoding][, callback]) 在 socket 上发送数据。第二个参数指定了字符串的编码,默认是 UTF8 编码。
6 socket.end([data][, encoding]) 半关闭 socket。例如,它发送一个 FIN 包。可能服务器仍在发送数据。
7 socket.destroy() 确保没有 I/O 活动在这个套接字上。只有在错误发生情况下才需要。(处理错误等等)。
8 socket.pause() 暂停读取数据。就是说,不会再触发 data 事件。对于控制上传非常有用。
9 socket.resume() 调用 pause() 后想恢复读取数据。
10 socket.setTimeout(timeout[, callback]) socket 闲置时间超过 timeout 毫秒后 ,将 socket 设置为超时。
11 socket.setNoDelay([noDelay]) 禁用纳格(Nagle)算法。默认情况下 TCP 连接使用纳格算法,在发送前他们会缓冲数据。将 noDelay 设置为 true 将会在调用 socket.write() 时立即发送数据。noDelay 默认值为 true。
12/td> socket.setKeepAlive([enable][, initialDelay]) 禁用/启用长连接功能,并在发送第一个在闲置 socket 上的长连接 probe 之前,可选地设定初始延时。默认为 false。 设定 initialDelay (毫秒),来设定收到的最后一个数据包和第一个长连接probe之间的延时。将 initialDelay 设为0,将会保留默认(或者之前)的值。默认值为0.
13 socket.address() 操作系统返回绑定的地址,协议族名和服务器端口。返回的对象有 3 个属性,比如{ port: 12346, family: 'IPv4', address: '127.0.0.1' }。
14 socket.unref() 如果这是事件系统中唯一一个活动的服务器,调用 unref 将允许程序退出。如果服务器已被 unref,则再次调用 unref 并不会产生影响。
15 socket.ref() 与 unref 相反,如果这是唯一的服务器,在之前被 unref 了的服务器上调用 ref 将不会让程序退出(默认行为)。如果服务器已经被 ref,则再次调用 ref 并不会产生影响。

实例 创建 server.js 文件,代码如下所示:

var net = require('net');
var server = net.createServer(function(connection) { 
   console.log('client connected');
   connection.on('end', function() {
      console.log('客户端关闭连接');
   });
   connection.write('Hello World!\r\n');
   connection.pipe(connection);
});
server.listen(8080, function() { 
  console.log('server is listening');
});

执行以上服务端代码:

$ node server.js
server is listening   # 服务已创建并监听 8080 端口

新开一个窗口,创建 client.js 文件,代码如下所示:

var net = require('net');
var client = net.connect({port: 8080}, function() {
   console.log('连接到服务器!');  
});
client.on('data', function(data) {
   console.log(data.toString());
   client.end();
});
client.on('end', function() { 
   console.log('断开与服务器的连接');
});

执行以上客户端的代码:

连接到服务器!
Hello World!

断开与服务器的连接

Gif 实例演示 nodejs08.gif

14.4 DNS模块

Node.js DNS 模块用于解析域名。引入 DNS 模块语法格式如下:

var dns = require("dns")

方法

序号 属性&描述
1 socket.bufferSize 该属性显示了要写入缓冲区的字节数。
2 socket.remoteAddress 远程的 IP 地址字符串,例如:'74.125.127.100' or '2001:4860:a005::68'。
3 socket.remoteFamily 远程IP协议族字符串,比如 'IPv4' or 'IPv6'。
4 socket.remotePort 远程端口,数字表示,例如:80 or 21。
5 socket.localAddress 网络连接绑定的本地接口 远程客户端正在连接的本地 IP 地址,字符串表示。例如,如果你在监听'0.0.0.0'而客户端连接在'192.168.1.1',这个值就会是 '192.168.1.1'。
6 socket.localPort 本地端口地址,数字表示。例如:80 or 21。
7 socket.bytesRead 接收到得字节数。
8 socket.bytesWritten 发送的字节数。

方法

序号 方法&描述
1 dns.lookup(hostname[, options], callback) 将域名(比如 'geekjc.com')解析为第一条找到的记录 A (IPV4)或 AAAA(IPV6)。参数 options可以是一个对象或整数。如果没有提供 options,IP v4 和 v6 地址都可以。如果 options 是整数,则必须是 4 或 6。
2 dns.lookupService(address, port, callback) 使用 getnameinfo 解析传入的地址和端口为域名和服务。
3 dns.resolve(hostname[, rrtype], callback) 将一个域名(如 'geekjc.com')解析为一个 rrtype 指定记录类型的数组。
4 dns.resolve4(hostname, callback) 和 dns.resolve() 类似, 仅能查询 IPv4 (A 记录)。 addresses IPv4 地址数组 (比如,['74.125.79.104', '74.125.79.105', '74.125.79.106'])。
5 dns.resolve6(hostname, callback) 和 dns.resolve4() 类似, 仅能查询 IPv6( AAAA 查询)
6 dns.resolveMx(hostname, callback) 和 dns.resolve() 类似, 仅能查询邮件交换(MX 记录)。
7 dns.resolveTxt(hostname, callback) 和 dns.resolve() 类似, 仅能进行文本查询 (TXT 记录)。 addresses 是 2-d 文本记录数组。(比如,[ ['v=spf1 ip4:0.0.0.0 ', '~all' ] ])。 每个子数组包含一条记录的 TXT 块。根据使用情况可以连接在一起,也可单独使用。
8 dns.resolveSrv(hostname, callback) 和 dns.resolve() 类似, 仅能进行服务记录查询 (SRV 记录)。 addresses 是 hostname可用的 SRV 记录数组。 SRV 记录属性有优先级(priority),权重(weight), 端口(port), 和名字(name) (比如,[{'priority': 10, 'weight': 5, 'port': 21223, 'name': 'service.example.com'}, ...])。
9 dns.resolveSoa(hostname, callback) 和 dns.resolve() 类似, 仅能查询权威记录(SOA 记录)。
10 dns.resolveNs(hostname, callback) 和 dns.resolve() 类似, 仅能进行域名服务器记录查询(NS 记录)。 addresses 是域名服务器记录数组(hostname 可以使用) (比如, ['ns1.example.com', 'ns2.example.com'])。
11 dns.resolveCname(hostname, callback) 和 dns.resolve() 类似, 仅能进行别名记录查询 (CNAME记录)。addresses 是对 hostname 可用的别名记录数组 (比如,, ['bar.example.com'])。
12/td> dns.reverse(ip, callback) 反向解析 IP 地址,指向该 IP 地址的域名数组。
13 dns.getServers() 返回一个用于当前解析的 IP 地址数组的字符串。
14 dns.setServers(servers) 指定一组 IP 地址作为解析服务器。

rrtypes 以下列出了 dns.resolve() 方法中有效的 rrtypes值:

  • 'A' IPV4 地址, 默认
  • 'AAAA' IPV6 地址
  • 'MX' 邮件交换记录
  • 'TXT' text 记录
  • 'SRV' SRV 记录
  • 'PTR' 用来反向 IP 查找
  • 'NS' 域名服务器记录
  • 'CNAME' 别名记录
  • 'SOA' 授权记录的初始值
错误码

每次 DNS 查询都可能返回以下错误码:

  • dns.NODATA: 无数据响应。
  • dns.FORMERR: 查询格式错误。
  • dns.SERVFAIL: 常规失败。
  • dns.NOTFOUND: 没有找到域名。
  • dns.NOTIMP: 未实现请求的操作。
  • dns.REFUSED: 拒绝查询。
  • dns.BADQUERY: 查询格式错误。
  • dns.BADNAME: 域名格式错误。
  • dns.BADFAMILY: 地址协议不支持。
  • dns.BADRESP: 回复格式错误。
  • dns.CONNREFUSED: 无法连接到 DNS 服务器。
  • dns.TIMEOUT: 连接 DNS 服务器超时。
  • dns.EOF: 文件末端。
  • dns.FILE: 读文件错误。
  • dns.NOMEM: 内存溢出。
  • dns.DESTRUCTION: 通道被摧毁。
  • dns.BADSTR: 字符串格式错误。
  • dns.BADFLAGS: 非法标识符。
  • dns.NONAME: 所给主机不是数字。
  • dns.BADHINTS: 非法HINTS标识符。
  • dns.NOTINITIALIZED: c c-ares 库尚未初始化。
  • dns.LOADIPHLPAPI: 加载 iphlpapi.dll 出错。
  • dns.ADDRGETNETWORKPARAMS: 无法找到 GetNetworkParams 函数。
  • dns.CANCELLED: 取消 DNS 查询。

实例 创建 main.js 文件,代码如下所示:

var dns = require('dns');

dns.lookup('www.github.com', function onLookup(err, address, family) {
   console.log('ip 地址:', address);
   dns.reverse(address, function (err, hostnames) {
   if (err) {
      console.log(err.stack);
   }

   console.log('反向解析 ' + address + ': ' + JSON.stringify(hostnames));
});  
});

执行以上代码,结果如下所示:

address: 192.30.252.130
reverse for 192.30.252.130: ["github.com"]

14.5 Domain模块

Node.js Domain(域) 简化异步代码的异常处理,可以捕捉处理try catch无法捕捉的异常。引入 Domain 模块 语法格式如下:

var domain = require("domain")

domain模块,把处理多个不同的IO的操作作为一个组。注册事件和回调到domain,当发生一个错误事件或抛出一个错误时,domain对象会被通知,不会丢失上下文环境,也不导致程序错误立即推出,与process.on('uncaughtException')不同。 Domain 模块可分为隐式绑定和显式绑定:

  • 隐式绑定: 把在domain上下文中定义的变量,自动绑定到domain对象
  • 显式绑定: 把不是在domain上下文中定义的变量,以代码的方式绑定到domain对象

方法

序号 方法&描述
1 domain.run(function) 在域的上下文运行提供的函数,隐式的绑定了所有的事件分发器,计时器和底层请求。
2 domain.add(emitter) 显式的增加事件
3 domain.remove(emitter) 删除事件。
4 domain.bind(callback) 返回的函数是一个对于所提供的回调函数的包装函数。当调用这个返回的函数被时,所有被抛出的错误都会被导向到这个域的 error 事件。
5 domain.intercept(callback) 和 domain.bind(callback) 类似。除了捕捉被抛出的错误外,它还会拦截 Error 对象作为参数传递到这个函数。
6 domain.enter() 进入一个异步调用的上下文,绑定到domain。
7 domain.exit() 退出当前的domain,切换到不同的链的异步调用的上下文中。对应domain.enter()。
8 domain.dispose() 释放一个domain对象,让node进程回收这部分资源。
9 domain.create() 返回一个domain对象。

属性

序号 属性&描述
1 domain.members 已加入domain对象的域定时器和事件发射器的数组。

实例 创建 main.js 文件,代码如下所示:

var EventEmitter = require("events").EventEmitter;
var domain = require("domain");

var emitter1 = new EventEmitter();

// 创建域
var domain1 = domain.create();

domain1.on('error', function(err){
   console.log("domain1 处理这个错误 ("+err.message+")");
});

// 显式绑定
domain1.add(emitter1);

emitter1.on('error',function(err){
   console.log("监听器处理此错误 ("+err.message+")");
});

emitter1.emit('error',new Error('通过监听器来处理'));

emitter1.removeAllListeners('error');

emitter1.emit('error',new Error('通过 domain1 处理'));

var domain2 = domain.create();

domain2.on('error', function(err){
   console.log("domain2 处理这个错误 ("+err.message+")");
});

// 隐式绑定
domain2.run(function(){
   var emitter2 = new EventEmitter();
   emitter2.emit('error',new Error('通过 domain2 处理'));   
});


domain1.remove(emitter1);
emitter1.emit('error', new Error('转换为异常,系统将崩溃!'));

执行以上代码,结果如下所示:

监听器处理此错误 (通过监听器来处理)
domain1 处理这个错误 (通过 domain1 处理)
domain2 处理这个错误 (通过 domain2 处理)

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: 转换为异常,系统将崩溃!
    at Object.<anonymous> (/www/node/main.js:40:24)
    at Module._compile (module.js:456:26)
    at Object.Module._extensions..js (module.js:474:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:312:12)
    at Function.Module.runMain (module.js:497:10)
    at startup (node.js:119:16)
    at node.js:929:3

15. Nodejs Web模块

Node.js Web模块

什么是 Web 服务器?

Web服务器一般指网站服务器,是指驻留于因特网上某种类型计算机的程序,Web服务器的基本功能就是提供Web信息浏览服务。它只需支持HTTP协议、HTML文档格式及URL,与客户端的网络浏览器配合。 大多数 web 服务器都支持服务端的脚本语言(php、python、ruby)等,并通过脚本语言从数据库获取数据,将结果返回给客户端浏览器。 目前最主流的三个Web服务器是Apache、Nginx、IIS。

Web 应用架构

nodejs09.jpg

  • Client - 客户端,一般指浏览器,浏览器可以通过 HTTP 协议向服务器请求数据。
  • Server - 服务端,一般指 Web 服务器,可以接收客户端请求,并向客户端发送响应数据。
  • Business - 业务层, 通过 Web 服务器处理应用程序,如与数据库交互,逻辑运算,调用外部程序等。
  • Data - 数据层,一般由数据库组成。

15.1 使用 Node 创建 Web 服务器

Node.js 提供了 http 模块,http 模块主要用于搭建 HTTP 服务端和客户端,使用 HTTP 服务器或客户端功能必须调用 http 模块,代码如下:

var http = require('http');

以下是演示一个最基本的 HTTP 服务器架构(使用8081端口),创建 server.js 文件,代码如下所示:

var http = require('http');
var fs = require('fs');
var url = require('url');


// 创建服务器
http.createServer( function (request, response) {  
   // 解析请求,包括文件名
   var pathname = url.parse(request.url).pathname;

   // 输出请求的文件名
   console.log("Request for " + pathname + " received.");

   // 从文件系统中读取请求的文件内容
   fs.readFile(pathname.substr(1), function (err, data) {
      if (err) {
         console.log(err);
         // HTTP 状态码: 404 : NOT FOUND
         // Content Type: text/plain
         response.writeHead(404, {'Content-Type': 'text/html'});
      }else{           
         // HTTP 状态码: 200 : OK
         // Content Type: text/plain
         response.writeHead(200, {'Content-Type': 'text/html'});  

         // 响应文件内容
         response.write(data.toString());   
      }
      //  发送响应数据
      response.end();
   });   
}).listen(8081);

// 控制台会输出以下信息
console.log('Server running at http://127.0.0.1:8081/');

接下来我们在该目录下创建一个 index.html 文件,代码如下:

<html>
<head>
<title>geekjc</title>
</head>
<body>
welcome to geekjc.com
</body>
</html>

执行 server.js 文件:

$ node server.js
Server running at http://127.0.0.1:8081/

接着我们在浏览器中打开地址:http://127.0.0.1:8081/index.htm,显示如下图所示: nodejs10.png 执行 server.js 的控制台输出信息如下:

Server running at http://127.0.0.1:8081/
Request for /index.html received.     #  客户端请求信息

15.2 使用 Node 创建 Web 客户端

Node 创建 Web 客户端需要引入 http 模块,创建 client.js 文件,代码如下所示:

var http = require('http');

// 用于请求的选项
var options = {
   host: 'localhost',
   port: '8081',
   path: '/index.html'  
};

// 处理响应的回调函数
var callback = function(response){
   // 不断更新数据
   var body = '';
   response.on('data', function(data) {
      body += data;
   });

   response.on('end', function() {
      // 数据接收完成
      console.log(body);
   });
}
// 向服务端发送请求
var req = http.request(options, callback);
req.end();

新开一个终端,执行 client.js 文件,输出结果如下:

$ node client.js
<html>
<head>
<title>Sample Page</title>
</head>
<body>
Hello World!
</body>
</html>

执行 server.js 的控制台输出信息如下:

Server running at http://127.0.0.1:8081/
Request for /index.html received.   # 客户端请求信息

16. Nodejs Express框架

Node.js Express 框架

16.1 Express 简介

Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具。 使用 Express 可以快速地搭建一个完整功能的网站。 Express 框架核心特性:

  • 可以设置中间件来响应 HTTP 请求。
  • 定义了路由表用于执行不同的 HTTP 请求动作。
  • 可以通过向模板传递参数来动态渲染 HTML 页面。

16.2 安装 Express

安装 Express 并将其保存到依赖列表中:

$ npm install express --save

以上命令会将 Express 框架安装在当前目录的 node_modules 目录中, node_modules 目录下会自动创建 express 目录。以下几个重要的模块是需要与 express 框架一起安装的:

  • body-parser - node.js 中间件,用于处理 JSON, Raw, Text 和 URL 编码的数据。
  • cookie-parser - 这就是一个解析Cookie的工具。通过req.cookies可以取到传过来的cookie,并把它们转成对象。
  • multer - node.js 中间件,用于处理 enctype="multipart/form-data"(设置表单的MIME编码)的表单数据。
$ npm install body-parser --save
$ npm install cookie-parser --save
$ npm install multer --save

16.3 第一个Express框架实例

接下来我们使用 Express 框架来输出 "Hello World"。 以下实例中我们引入了 express 模块,并在客户端发起请求后,响应 "Hello World" 字符串。 创建 express_demo.js 文件,代码如下所示:

//express_demo.js 文件
var express = require('express');
var app = express();

app.get('/', function (req, res) {
   res.send('Hello World');
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

执行以上代码:

$ node express_demo.js 
应用实例,访问地址为 http://0.0.0.0:8081

在浏览器中访问 http://127.0.0.1:8081 , 显示Hello World

16.4 请求和响应

Express 应用使用回调函数的参数: request 和 response 对象来处理请求和响应的数据。

app.get('/', function (req, res) {
   // --
})

requestresponse 对象的具体介绍: Request 对象 - request 对象表示 HTTP 请求,包含了请求查询字符串,参数,内容,HTTP 头部等属性。常见属性有:

  • req.app:当callback为外部文件时,用req.app访问express的实例
  • req.baseUrl:获取路由当前安装的URL路径
  • req.body / req.cookies:获得「请求主体」/ Cookies
  • req.fresh / req.stale:判断请求是否还「新鲜」
  • req.hostname / req.ip:获取主机名和IP地址
  • req.originalUrl:获取原始请求URL
  • req.params:获取路由的parameters
  • req.path:获取请求路径
  • req.protocol:获取协议类型
  • req.query:获取URL的查询参数串
  • req.route:获取当前匹配的路由
  • req.subdomains:获取子域名
  • req.accepts():检查可接受的请求的文档类型
  • req.acceptsCharsets / req.acceptsEncodings / req.acceptsLanguages:返回指定字符集的第一个可接受字符编码
  • req.get():获取指定的HTTP请求头
  • req.is():判断请求头Content-Type的MIME类型

Response对象 - response 对象表示 HTTP 响应,即在接收到请求时向客户端发送的 HTTP 响应数据。常见属性有:

  • res.app:同req.app一样
  • res.append():追加指定HTTP头
  • res.set()在res.append()后将重置之前设置的头
  • res.cookie(name,value [,option]):设置Cookie
  • opition: domain / expires / httpOnly / maxAge / path / secure / signed
  • res.clearCookie():清除Cookie
  • res.download():传送指定路径的文件
  • res.get():返回指定的HTTP头
  • res.json():传送JSON响应
  • res.jsonp():传送JSONP响应
  • res.location():只设置响应的Location HTTP头,不设置状态码或者close response
  • res.redirect():设置响应的Location HTTP头,并且设置状态码302
  • res.send():传送HTTP响应
  • res.sendFile(path [,options] [,fn]):传送指定路径的文件 -会自动根据文件extension设定Content-Type
  • res.set():设置HTTP头,传入object可以一次设置多个头
  • res.status():设置HTTP状态码
  • res.type():设置Content-Type的MIME类型

16.5 路由

我们已经了解了 HTTP 请求的基本应用,而路由决定了由谁(指定脚本)去响应客户端请求。 在HTTP请求中,我们可以通过路由提取出请求的URL以及GET/POST参数。 接下来我们扩展 Hello World,添加一些功能来处理更多类型的 HTTP 请求。 创建 express_demo2.js 文件,代码如下所示:

var express = require('express');
var app = express();

//  主页输出 "Hello World"
app.get('/', function (req, res) {
   console.log("主页 GET 请求");
   res.send('Hello GET');
})


//  POST 请求
app.post('/', function (req, res) {
   console.log("主页 POST 请求");
   res.send('Hello POST');
})

//  /del_user 页面响应
app.get('/del_user', function (req, res) {
   console.log("/del_user 响应 DELETE 请求");
   res.send('删除页面');
})

//  /list_user 页面 GET 请求
app.get('/list_user', function (req, res) {
   console.log("/list_user GET 请求");
   res.send('用户列表页面');
})

// 对页面 abcd, abxcd, ab123cd, 等响应 GET 请求
app.get('/ab*cd', function(req, res) {   
   console.log("/ab*cd GET 请求");
   res.send('正则匹配');
})


var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

执行以上代码:

$ node express_demo2.js 
应用实例,访问地址为 http://0.0.0.0:8081

接下来你可以尝试访问 http://127.0.0.1:8081 不同的地址,查看效果。

16.6 静态文件

Express 提供了内置的中间件 express.static 来设置静态文件如:图片, CSS, JavaScript 等。 你可以使用 express.static 中间件来设置静态文件路径。例如,如果你将图片, CSS, JavaScript 文件放在 public 目录下,你可以这么写:

app.use(express.static('public'));

我们可以到 public/images 目录下放些图片,如下所示:

node_modules
server.js
public/
public/images
public/images/geekjc.png

让我们再修改下 "Hello World" 应用添加处理静态文件的功能。 创建 express_demo3.js 文件,代码如下所示:

var express = require('express');
var app = express();

app.use(express.static('public'));

app.get('/', function (req, res) {
   res.send('Hello World');
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

执行以上代码:

$ node express_demo3.js 
应用实例,访问地址为 http://0.0.0.0:8081

然后就可以在浏览器输入文件路径访问文件。

16.7 GET方法

以下实例演示了在表单中通过 GET 方法提交两个参数,我们可以使用 server.js 文件内的 process_get 路由器来处理输入: index.htm 文件代码如下:

<html>
<body>
<form action="http://127.0.0.1:8081/process_get" method="GET">
First Name: <input type="text" name="first_name">  <br>

Last Name: <input type="text" name="last_name">
<input type="submit" value="Submit">
</form>
</body>
</html>

server.js 文件代码如下:

var express = require('express');
var app = express();

app.use(express.static('public'));

app.get('/index.htm', function (req, res) {
   res.sendFile( __dirname + "/" + "index.htm" );
})

app.get('/process_get', function (req, res) {

   // 输出 JSON 格式
   response = {
       first_name:req.query.first_name,
       last_name:req.query.last_name
   };
   console.log(response);
   res.end(JSON.stringify(response));
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

执行以上代码:

node server.js 
应用实例,访问地址为 http://0.0.0.0:8081

然后浏览器访问http://127.0.0.1:8081/index.htm

16.8 POST方法

以下实例演示了在表单中通过 POST 方法提交两个参数,我们可以使用 server.js 文件内的 process_post 路由器来处理输入: index.htm 文件代码修改如下:

<html>
<body>
<form action="http://127.0.0.1:8081/process_post" method="POST">
First Name: <input type="text" name="first_name">  <br>

Last Name: <input type="text" name="last_name">
<input type="submit" value="Submit">
</form>
</body>
</html>

server.js 文件代码修改如下:

var express = require('express');
var app = express();
var bodyParser = require('body-parser');

// 创建 application/x-www-form-urlencoded 编码解析
var urlencodedParser = bodyParser.urlencoded({ extended: false })

app.use(express.static('public'));

app.get('/index.htm', function (req, res) {
   res.sendFile( __dirname + "/" + "index.htm" );
})

app.post('/process_post', urlencodedParser, function (req, res) {

   // 输出 JSON 格式
   response = {
       first_name:req.body.first_name,
       last_name:req.body.last_name
   };
   console.log(response);
   res.end(JSON.stringify(response));
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

执行以上代码:

$ node server.js
应用实例,访问地址为 http://0.0.0.0:8081

然后浏览器访问http://127.0.0.1:8081/index.htm查看效果

16.9 文件上传

以下我们创建一个用于上传文件的表单,使用 POST 方法,表单 enctype 属性设置为 multipart/form-data。 index.htm 文件代码修改如下:

<html>
<head>
<title>文件上传表单</title>
</head>
<body>
<h3>文件上传:</h3>
选择一个文件上传: <br />
<form action="/file_upload" method="post" enctype="multipart/form-data">
<input type="file" name="image" size="50" />
<br />
<input type="submit" value="上传文件" />
</form>
</body>
</html>

server.js 文件代码修改如下:

var express = require('express');
var app = express();
var fs = require("fs");

var bodyParser = require('body-parser');
var multer  = require('multer');

app.use(express.static('public'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(multer({ dest: '/tmp/'}).array('image'));

app.get('/index.htm', function (req, res) {
   res.sendFile( __dirname + "/" + "index.htm" );
})

app.post('/file_upload', function (req, res) {

   console.log(req.files[0]);  // 上传的文件信息

   var des_file = __dirname + "/" + req.files[0].originalname;
   fs.readFile( req.files[0].path, function (err, data) {
        fs.writeFile(des_file, data, function (err) {
         if( err ){
              console.log( err );
         }else{
               response = {
                   message:'File uploaded successfully', 
                   filename:req.files[0].originalname
              };
          }
          console.log( response );
          res.end( JSON.stringify( response ) );
       });
   });
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

执行以上代码:

$ node server.js 
应用实例,访问地址为 http://0.0.0.0:8081

然后浏览器访问http://127.0.0.1:8081/index.htm查看效果

16.10 Cookie 管理

我们可以使用中间件向 Node.js 服务器发送 cookie 信息,以下代码输出了客户端发送的 cookie 信息:

// express_cookie.js 文件
var express      = require('express')
var cookieParser = require('cookie-parser')

var app = express()
app.use(cookieParser())

app.get('/', function(req, res) {
  console.log("Cookies: ", req.cookies)
})

app.listen(8081)

执行以上代码:

$ node express_cookie.js

现在你可以访问 http://127.0.0.1:8081 并查看终端信息的输出

16.11 相关资料

17. Nodejs RESTfult API

Node.js RESTful API

17.1 什么是REST?

REST即表述性状态传递(英文:Representational State Transfer,简称REST)是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。 表述性状态转移是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful。需要注意的是,REST是设计风格而不是标准。REST通常基于使用HTTP,URI,和XML(标准通用标记语言下的一个子集)以及HTML(标准通用标记语言下的一个应用)这些现有的广泛流行的协议和标准。REST 通常使用 JSON 数据格式。

17.1.1 HTTP 方法

以下为 REST 基本架构的四个方法:

  • GET - 用于获取数据。
  • PUT - 用于添加数据。
  • DELETE - 用于删除数据。
  • POST - 用于更新或添加数据。

17.2 RESTful Web Services

Web service是一个平台独立的,低耦合的,自包含的、基于可编程的web的应用程序,可使用开放的XML(标准通用标记语言下的一个子集)标准来描述、发布、发现、协调和配置这些应用程序,用于开发分布式的互操作的应用程序。 基于 REST 架构的 Web Services 即是 RESTful。 由于轻量级以及通过 HTTP 直接传输数据的特性,Web 服务的 RESTful 方法已经成为最常见的替代方法。可以使用各种语言(比如 Java 程序、Perl、Ruby、Python、PHP 和 Javascript[包括 Ajax])实现客户端。 RESTful Web 服务通常可以通过自动客户端或代表用户的应用程序访问。但是,这种服务的简便性让用户能够与之直接交互,使用它们的 Web 浏览器构建一个 GET URL 并读取返回的内容。 更多介绍,可以查看:RESTful 架构详解

17.3 创建 RESTful

首先,创建一个 json 数据资源文件 users.json,内容如下:

{
   "user1" : {
      "name" : "mahesh",
      "password" : "password1",
      "profession" : "teacher",
      "id": 1
   },
   "user2" : {
      "name" : "suresh",
      "password" : "password2",
      "profession" : "librarian",
      "id": 2
   },
   "user3" : {
      "name" : "ramesh",
      "password" : "password3",
      "profession" : "clerk",
      "id": 3
   }
}

基于以上数据,我们创建以下 RESTful API:

序号 URL HTTP方法 发送内容 结果
1 listUsers GET 显示所有用户列表
2 addUser POST JSON字符串 添加新用户
3 deleteUser DELETE JSON字符串 删除用户
4 :id GET 显示用户详细信息

17.4 获取用户列表

以下代码,我们创建了 RESTful API listUsers,用于读取用户的信息列表, server.js 文件代码如下所示:

var express = require('express');
var app = express();
var fs = require("fs");

app.get('/listUsers', function (req, res) {
   fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
       console.log( data );
       res.end( data );
   });
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

接下来执行以下命令:

$ node server.js 
应用实例,访问地址为 http://0.0.0.0:8081

在浏览器中访问 http://127.0.0.1:8081/listUsers ,结果如下所示:

{
   "user1" : {
      "name" : "mahesh",
      "password" : "password1",
      "profession" : "teacher",
      "id": 1
   },
   "user2" : {
      "name" : "suresh",
      "password" : "password2",
      "profession" : "librarian",
      "id": 2
   },
   "user3" : {
      "name" : "ramesh",
      "password" : "password3",
      "profession" : "clerk",
      "id": 3
   }
}

17.5 添加用户

以下代码,我们创建了 RESTful API addUser, 用于添加新的用户数据,server.js 文件代码如下所示:

var express = require('express');
var app = express();
var fs = require("fs");

//添加的新用户数据
var user = {
   "user4" : {
      "name" : "mohit",
      "password" : "password4",
      "profession" : "teacher",
      "id": 4
   }
}

app.get('/addUser', function (req, res) {
   // 读取已存在的数据
   fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
       data = JSON.parse( data );
       data["user4"] = user["user4"];
       console.log( data );
       res.end( JSON.stringify(data));
   });
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port
  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

接下来执行以下命令:

$ node server.js 
应用实例,访问地址为 http://0.0.0.0:8081

在浏览器中访问 http://127.0.0.1:8081/addUser ,结果如下所示:

{ user1:
   { name: 'mahesh',
     password: 'password1',
     profession: 'teacher',
     id: 1 },
  user2:
   { name: 'suresh',
     password: 'password2',
     profession: 'librarian',
     id: 2 },
  user3:
   { name: 'ramesh',
     password: 'password3',
     profession: 'clerk',
     id: 3 },
  user4:
   { name: 'mohit',
     password: 'password4',
     profession: 'teacher',
     id: 4 } 
}

17.6 显示用户详情

以下代码,我们创建了 RESTful API:id(用户id), 用于读取指定用户的详细信息,server.js 文件代码如下所示:

var express = require('express');
var app = express();
var fs = require("fs");

app.get('/:id', function (req, res) {
   // 首先我们读取已存在的用户
   fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
       data = JSON.parse( data );
       var user = data["user" + req.params.id] 
       console.log( user );
       res.end( JSON.stringify(user));
   });
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port
  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

接下来执行以下命令:

$ node server.js 
应用实例,访问地址为 http://0.0.0.0:8081

在浏览器中访问 http://127.0.0.1:8081/2 ,结果如下所示:

{
   "name":"suresh",
   "password":"password2",
   "profession":"librarian",
   "id":2
}

17.7 删除用户

以下代码,我们创建了 RESTful API deleteUser, 用于删除指定用户的详细信息,以下实例中,用户 id 为 2,server.js 文件代码如下所示:

var express = require('express');
var app = express();
var fs = require("fs");

var id = 2;

app.get('/deleteUser', function (req, res) {

   // First read existing users.
   fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
       data = JSON.parse( data );
       delete data["user" + 2];

       console.log( data );
       res.end( JSON.stringify(data));
   });
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port
  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

接下来执行以下命令:

$ node server.js 
应用实例,访问地址为 http://0.0.0.0:8081

在浏览器中访问 http://127.0.0.1:8081/deleteUser ,结果如下所示:

{ user1:
   { name: 'mahesh',
     password: 'password1',
     profession: 'teacher',
     id: 1 },
  user3:
   { name: 'ramesh',
     password: 'password3',
     profession: 'clerk',
     id: 3 } 
}

18. Nodejs多进程

Node.js多进程 我们都知道 Node.js 是以单线程的模式运行的,但它使用的是事件驱动来处理并发,这样有助于我们在多核 cpu 的系统上创建多个子进程,从而提高性能。 每个子进程总是带有三个流对象:child.stdin, child.stdout 和child.stderr。他们可能会共享父进程的 stdio 流,或者也可以是独立的被导流的流对象。 Node 提供了 child_process 模块来创建子进程,方法有:

  • exec- child_process.exec 使用子进程执行命令,缓存子进程的输出,并将子进程的输出以回调函数参数的形式返回。
  • spawn- child_process.spawn 使用指定的命令行参数创建新进程。
  • fork- child_process.fork 是 spawn()的特殊形式,用于在子进程中运行的模块,如 fork('./son.js') 相当于 spawn('node', ['./son.js']) 。与spawn方法不同的是,fork会在父进程与子进程之间,建立一个通信管道,用于进程之间的通信。

18.1 exec()方法

child_process.exec 使用子进程执行命令,缓存子进程的输出,并将子进程的输出以回调函数参数的形式返回。 语法如下所示:

child_process.exec(command[, options], callback)

参数 参数说明如下: command: 字符串, 将要运行的命令,参数使用空格隔开 options :对象,可以是:

  • cwd ,字符串,子进程的当前工作目录
  • env,对象 环境变量键值对
  • encoding ,字符串,字符编码(默认: 'utf8')
  • shell ,字符串,将要执行命令的 Shell(默认: 在 UNIX 中为/bin/sh, 在 Windows 中为cmd.exe, Shell 应当能识别 -c开关在 UNIX 中,或 /s /c 在 Windows 中。 在Windows 中,命令行解析应当能兼容cmd.exe)
  • timeout,数字,超时时间(默认: 0)
  • maxBuffer,数字, 在 stdout 或 stderr 中允许存在的最大缓冲(二进制),如果超出那么子进程将会被杀死 (默认: 200*1024)
  • killSignal ,字符串,结束信号(默认:'SIGTERM')
  • uid,数字,设置用户进程的 ID
  • gid,数字,设置进程组的 ID

callback :回调函数,包含三个参数error, stdout 和 stderr。 exec() 方法返回最大的缓冲区,并等待进程结束,一次性返回缓冲区的内容。

实例 让我们创建两个 js 文件 support.js 和 master.js。 support.js 文件代码:

console.log("进程 " + process.argv[2] + " 执行。" );

master.js 文件代码:

const fs = require('fs');
const child_process = require('child_process');

for(var i=0; i<3; i++) {
   var workerProcess = child_process.exec('node support.js '+i,
      function (error, stdout, stderr) {
         if (error) {
            console.log(error.stack);
            console.log('Error code: '+error.code);
            console.log('Signal received: '+error.signal);
         }
         console.log('stdout: ' + stdout);
         console.log('stderr: ' + stderr);
      });

      workerProcess.on('exit', function (code) {
      console.log('子进程已退出,退出码 '+code);
   });
}

执行以上代码,输出结果为:

$ node master.js 
子进程已退出,退出码 0
stdout: 进程 1 执行。

stderr: 
子进程已退出,退出码 0
stdout: 进程 0 执行。

stderr: 
子进程已退出,退出码 0
stdout: 进程 2 执行。

stderr:

18.2 spawn() 方法

child_process.spawn 使用指定的命令行参数创建新进程,语法格式如下:

child_process.spawn(command[, args][, options])

参数 参数说明如下: command: 将要运行的命令 args: Array 字符串参数数组 options Object

  • cwd String 子进程的当前工作目录
  • env Object 环境变量键值对
  • stdio Array|String 子进程的 stdio 配置
  • detached Boolean 这个子进程将会变成进程组的领导
  • uid Number 设置用户进程的 ID
  • gid Number 设置进程组的 ID

spawn() 方法返回流 (stdout & stderr),在进程返回大量数据时使用。进程一旦开始执行时 spawn() 就开始接收响应。

实例 让我们创建两个 js 文件 support.js 和 master.js。 support.js 文件代码:

console.log("进程 " + process.argv[2] + " 执行。" );

master.js 文件代码:

const fs = require('fs');
const child_process = require('child_process');

for(var i=0; i<3; i++) {
   var workerProcess = child_process.spawn('node', ['support.js', i]);

   workerProcess.stdout.on('data', function (data) {
      console.log('stdout: ' + data);
   });

   workerProcess.stderr.on('data', function (data) {
      console.log('stderr: ' + data);
   });

   workerProcess.on('close', function (code) {
      console.log('子进程已退出,退出码 '+code);
   });
}

执行以上代码,输出结果为:

$ node master.js stdout: 进程 0 执行。

子进程已退出,退出码 0
stdout: 进程 1 执行。

子进程已退出,退出码 0
stdout: 进程 2 执行。

子进程已退出,退出码 0

18.3 fork方法

child_process.fork 是 spawn() 方法的特殊形式,用于创建进程,语法格式如下:

child_process.fork(modulePath[, args][, options])

参数 数说明如下: modulePath: String,将要在子进程中运行的模块 args: Array 字符串参数数组 options:Object

  • cwd String 子进程的当前工作目录
  • env Object 环境变量键值对
  • execPath String 创建子进程的可执行文件
  • execArgv Array 子进程的可执行文件的字符串参数数组(默认: process.execArgv)
  • silent Boolean 如果为true,子进程的stdin,stdout和stderr将会被关联至父进程,否则,它们将会从父进程中继承。(默认为:false)
  • uid Number 设置用户进程的 ID
  • gid Number 设置进程组的 ID

返回的对象除了拥有ChildProcess实例的所有方法,还有一个内建的通信信道。 h3>实例 让我们创建两个 js 文件 support.js 和 master.js。 support.js 文件代码:

console.log("进程 " + process.argv[2] + " 执行。" );

master.js 文件代码:

const fs = require('fs');
const child_process = require('child_process');

for(var i=0; i<3; i++) {
   var worker_process = child_process.fork("support.js", [i]);  

   worker_process.on('close', function (code) {
      console.log('子进程已退出,退出码 ' + code);
   });
}

执行以上代码,输出结果为:

$ node master.js 
进程 0 执行。
子进程已退出,退出码 0
进程 1 执行。
子进程已退出,退出码 0
进程 2 执行。
子进程已退出,退出码 0

19. Nodejs JXcore打包

Node.js JXcore打包 Node.js 是一个开放源代码、跨平台的、用于服务器端和网络应用的运行环境。 JXcore 是一个支持多线程的 Node.js 发行版本,基本不需要对你现有的代码做任何改动就可以直接线程安全地以多线程运行。 但我们这篇文章主要是要教大家介绍 JXcore 的打包功能。

19.1 JXcore安装

下载 JXcore 安装包,并解压,在解压的的目录下提供了 jx 二进制文件命令,接下来我们主要使用这个命令 步骤1、下载 下载 JXcore 安装包 https://github.com/jxcore/jxcore-release,你需要根据你自己的系统环境来下载安装包。 1、Window 平台下载:Download(Windows x64 (V8))。 2、Linux/OSX 安装命令:

$ curl http://jxcore.com/xil.sh | bash

如果权限不足,可以使用以下命令:

curl http://jxcore.com/xil.sh | sudo bash

以上步骤如果操作正确,使用以下命令,会输出版本号信息:

$ jx --version
v0.10.32

19.2 包代码

例如,我们的 Node.js 项目包含以下几个文件,其中 index.js 是主文件:

drwxr-xr-x  2 root root  4096 Nov 13 12:42 images
-rwxr-xr-x  1 root root 30457 Mar  6 12:19 index.htm
-rwxr-xr-x  1 root root 30452 Mar  1 12:54 index.js
drwxr-xr-x 23 root root  4096 Jan 15 03:48 node_modules
drwxr-xr-x  2 root root  4096 Mar 21 06:10 scripts
drwxr-xr-x  2 root root  4096 Feb 15 11:56 style

接下来我们使用 jx 命令打包以上项目,并指定 index.js 为 Node.js 项目的主文件:

$ jx package index.js index

以上命令执行成功,会生成以下两个文件:

  • index.jxp 这是一个中间件文件,包含了需要编译的完整项目信息。
  • index.jx 这是一个完整包信息的二进制文件,可运行在客户端上。

19.3 载入JX文件

我们使用 jx 命令打包项目:

$ node index.js command_line_arguments

使用 JXcore 编译后,我们可以使用以下命令来执行生成的 jx 二进制文件:

$ jx index.jx command_line_arguments

更多 JXcore 功能特性你可以参考官网:http://jxcore.com/

本系列教程完

本教程分为三部分:

极客教程网
——一个你值得来的网站
编程笔记:学习分享,与君共勉!
轮子库:介绍各种库、插件的用途
在线工具:极客工具,在线工具,在线运行
前端导航:前端导航,前端资源聚合平台
分享
QQ群:
495489065

Copyright © 2017 - ~ All Rights Reserved. Made By Snow 备案号:粤ICP备15001588号-4