使用node.js进行服务器端JavaScript编程(1)(2)
常用模块
node.js 默认提供了很多与网络与文件系统操作相关的模块。这些模块是构建服务器端应用的基础。下面对其中一些常见的模块进行具体说明。
事件模块
前面提到过,node.js 采用的是事件驱动的架构,其中的很多模块都会产生各种不同的事件,可以由模块使用者来添加事件处理方法。所有能够产生事件的对象都是事件模块中的 EventEmitter 类的实例。
EventEmitter 类中的方法都与事件的产生和处理相关,如下所示:
◆ addListener(event, listener) 和 on(event, listener) :这两个方法的作用都是用来为某个事件 event 添加事件处理方法listener 。
◆ once(event, listener) :这个方法为某个事件 event 添加仅执行一次的处理方法 listener 。处理方法在执行一次之后就会被删除。
◆ removeListener(event, listener) :该方法用来删除某个事件 event 上的处理方法 listener 。
◆ emit(event, [arg1], [arg2], [...]) :该方法用来产生某个事件 event 。事件名称 event 之后的参数被传递给对应的事件处理方法。
代码清单 6 给出了事件模块的使用示例。
清单 6. 事件模块的使用示例
- var events = require("events");
- var emitter = new events.EventEmitter();
- emitter.on("myEvent", function(msg) {
- console.log(msg);
- });
- emitter.emit("myEvent", "Hello World.");
在事件模块中有一个特殊的事件 error 。当出现错误的时候,EventEmitter 会产生此事件。如果此事件没有对应的处理方法的话,默认的行为是输出错误信息后,程序自动终止。因此,需要注意总是添加一个对 error 事件的处理方法。
流
node.js 中存在各式各样不同的数据流,包括文件系统、HTTP 请求和响应、以及 TCP/UDP 连接等。这些流都是 EventEmitter 的实例,因此可以产生各种不同的事件。流可以分成只读、只写和读写流三种。
可读流主要会产生 4 个事件:
◆ data :当读取到流中的数据时,产生此事件。
◆ end :当流中没有数据可读时,产生此事件。
◆ error :当读取数据出现错误时,产生此事件。
◆ close :当流被关闭时,产生此事件。
除了上面的事件之外,还有一个 pipe() 方法可以用来把当前的可读流和另外一个可写流连接起来。可读流中的数据会被自动写入到可写流中。
可写流中最常用的是 write() 和 end() 两个方法。write() 方法用来向流中写入数据,而 end() 则用来结束写入操作。
为了表示二进制数据,node.js 使用了类 Buffer 来表示数据缓冲区,以对二进制数据进行操作。Buffer 类内部是以数组的方式来存储数据的。一旦创建出来之后,Buffer 的大小是不能被修改的。Buffer 类的实例是可以与 JavaScript 中的字符串类型互相转换的。在转换的时候需要指定编码格式。通过 Buffer 类的 toString(encoding, start, end) 方法可以把 Buffer 中的从 start 到 end 的内容转换成以 encoding 编码的字符串。可以支持的编码格式有:ascii 、utf8 和 base64 。通过 new Buffer(str, encoding) 可以用一个字符串 str 来初始化一个缓冲区。write(string, offset, encoding) 用来把一个字符串 string 以编码格式 encoding 写入到缓冲区中以 offset 开始的位置上。
网络操作
node.js 提供了一些与网络操作相关的模块,包括 TCP、UDP 和 HTTP 等,可以实现网络服务器和客户端。
与 TCP 协议相关的实现在 net 模块中。通过该模块的 createServer(connectionListener) 方法可以创建一个 TCP 服务器。参数connectionListener 是当有客户端连接到该服务器上时的处理方法,等价于对 connect 事件的处理。一个 TCP 服务器是类 Server 的实例。通过 listen 方法可以让服务器在指定端口监听。
如果想连接到一个已有的 TCP 服务器的话,可以使用 createConnection(port, host) 方法来连接到指定主机 host 的端口 port 上。该方法的返回值是 Socket 类的实例,表示一个套接字连接。得到一个 Socket 类的实例之后,就可以通过 write() 方法来向该连接中写入数据。如果想从该连接上获取数据的话,可以添加 data 事件的处理方法。
代码清单 7 中给出了一个简单的用来进行表达式计算的 TCP 服务器,可以通过 telnet 命令连接到此服务器来进行测试。
清单 7. 简单的表达式计算服务器
- var net = require("net");
- var server = net.createServer(function(socket) {
- socket.setEncoding("utf8");
- var buffer = [], len = 0;
- socket.on("data", function(data) { // 接收到客户端数据
- if (data.charCodeAt(0) == 13) {
- var expr = buffer.join("");
- try {
- var result = eval(expr); // 进行计算
- socket.write(result.toString()); // 写回结果
- } catch (e) {
- socket.write("Wrong expression.");
- } finally {
- socket.write("rn");
- buffer = [];
- }
- }
- else {
- buffer.push(data);
- }
- });
- });
- server.listen(8180, "127.0.0.1");
- console.log("服务器已经在端口 8180 启动。");
除了 TCP 服务器外,模块 http 和 https 可以分别实现 HTTP 和 HTTPS 服务器,模块 dgram 可以实现 UDP/Datagram 套接字连接,模块 tls 可以实现安全的套接字连接(SSL)。这些模块的使用方式都类似于模块 tcp 。
文件系统
node.js 中的 fs 模块用来对本地文件系统进行操作。fs 模块中提供的方法可以用来执行基本的文件操作,包括读、写、重命名、创建和删除目录以及获取文件元数据等。每个操作文件的方法都有同步和异步两个版本。异步操作的版本都会使用一个回调方法作为最后一个参数。当操作完成的时候,该回调方法会被调用。而回调方法的第一个参数总是保留为操作时可能出现的异常。如果操作正确成功,则第一个参数的值是 null 或 undefined 。而同步操作的版本的方法名称则是在对应的异步方法之后加上一个 Sync 作为后缀。比如异步的 rename() 方法的同步版本是 renameSync() 。下面列出来了 fs 模块中的一些常用方法,都只介绍异步操作的版本。
◆ rename(path1, path2) :将路径 path1 表示的目录或文件重命名成路径 path2 。
◆ truncate(fd, len) :将文件描述符 fd 对应的文件的长度截断为 len 。
◆ chmod(path, mode) :将路径 path 表示的目录或文件的权限修改为 mode 。
◆ stat(path) :获取路径 path 表示的目录或文件的元数据。元数据用 Stats 类来表示。
◆ open(path, flags, mode) :打开一个路径 path 表示的文件。回调方法中可以得到该文件的描述符。
◆ read(fd, buffer, offset, length, position) :读取给定文件描述符 fd 所表示的文件中从 position 位置开始的长度为length 字节的数据,并存放到缓冲区 buffer 中从 offset 起始的位置上。回调方法中可以得到实际读取的字节数。
◆ write(fd, buffer, offset, length, position) :将缓冲区 buffer 中的数据写入到文件描述符 fd 所表示的文件中。参数的含义与 read() 方法一样。回调方法中可以得到实际写入的字节数。
◆ readFile(filename, encoding) :以编码格式 encoding 来读取一个文件 filename 中的内容。回调方法中可以得到文件的内容。
◆ writeFile(filename, data, encoding) :将数据 data 以编码格式 encoding 写入到文件 filename 中。
除了上面列出来的直接操作文件本身的方法外,还可以把文件转换成流。createReadStream(path, options) 和createWriteStream(path, options) 分别用来从文件中创建可读和可写流。参数 path 表示的是文件的路径,options 是一个表示读取或写入文件时的选项的 JavaScript 对象。
代码清单 8 中给出了一个简单的 HTTP 静态文件服务器的实现。
清单 8. HTTP 静态文件服务器
- var http = require("http"),
- fs = require("fs"),
- path = require("path"),
- url = require("url");
- var server = http.createServer(function(req, res) {
- var pathname = url.parse(req.url).pathname;
- var filepath = path.join("/tmp", "wwwroot", pathname);
- var stream = fs.createReadStream(filepath, {flags : "r", encoding : null});
- stream.on("error", function() {
- res.writeHead(404);
- res.end();
- });
- stream.pipe(res);
- });
- server.on("error", function(error) {
- console.log(error);
- });
- server.listen(8088, "127.0.0.1");
如代码清单 8 所示,首先把 HTTP 请求的路径转换成服务器上文件路径,再从文件中创建可读流,最后通过 pipe() 方法把文件的数据流传递到 HTTP 请求的响应中。
- 上一篇:jQuery是如何工作的
- 下一篇:jQuery设计思想(1)