-- 运行在服务器端的javascript
一、创建HTTP Server
var http = require('http');
http.createServer(function (request, response) {
response.writeHead(200,{'Content-Type': 'text/plain'});
response.end('HelloWorld\n');
}).listen(8888);
第一行请求(require)Node.js 自带的 http 模块,并且把它赋值给 http变量。
接下来我们调用 http 模块提供的函数: createServer 。这个函数会返回一个对象,这个对象有一个叫做 listen 的方法,这个方法有一个数值参数, 指定这个 HTTP 服务器监听的端口号。
二、模块系统
为了让Node.js的文件可以相互调用,Node.js提供了一个简单的模块系统。
模块是Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个Node.js 文件就是一个模块,这个文件可能是JavaScript 代码、JSON 或者编译过的C/C++ 扩展。
Node.js 提供了exports 和 require 两个对象,其中 exports 是模块公开的接口,require 用于从外部获取一个模块的接口,即所获取模块的 exports 对象。
接下来我们就来创建hello.js文件,代码如下:
1 2 3 | exports.world = function() { console.log('Hello World'); } |
在以上示例中,hello.js 通过 exports 对象把 world 作为模块的访问接口,在 main.js 中通过require('./hello') 加载这个模块,然后就可以直接访 问main.js 中 exports 对象的成员函数了。
如下我们创建一个 'main.js' 文件,代码如下:
1 2 | var hello = require('./hello'); hello.world(); |
有时候我们只是想把一个对象封装到模块中,格式如下:
1 2 3 | module.exports = function() { // ... } |
例如:
1 2 3 4 5 6 7 8 9 10 11 | //hello.js functionHello() { varname; this.setName = function(thyName) { name = thyName; }; this.sayHello = function() { console.log('Hello ' + name); }; }; module.exports = Hello; |
这样就可以直接获得这个对象了:
1 2 3 4 5 | //main.js varHello = require('./hello'); hello = new Hello(); hello.setName('BYVoid'); hello.sayHello(); |
三、事件
产生事件的对象都是events.EventEmitter 的实例。 你可以通过require("events");来访问该模块。
1 2 3 4 5 6 7 8 9 | //event.js var EventEmitter = require('events').EventEmitter; var event = new EventEmitter(); event.on('some_event', function() { console.log('some_event occured.'); }); setTimeout(function() { event.emit('some_event'); }, 1000); |
events 模块只提供了一个对象:events.EventEmitter。EventEmitter的核心就是事件发射与事件监听器功能的封装。
EventEmitter的每个事件由一个事件名和若干个参数组成,事件名是一个字符串,通常表达一定的语义。对于每个事件,EventEmitter支持若干个事件监听器。
其他EventEmitter常用API:
EventEmitter.on(event,listener)、emitter.addListener(event, listener)为指定事件注册一个监听器,接受一个字 符串event和一个回调函数listener。
EventEmitter.emit(event,[arg1], [arg2], [...])发射event事件,传递若干可选参数到事件监听器的参数表。
EventEmitter.once(event,listener)为指定事件注册一个单次监听器,即监听器最多只会触发一次,触发后立刻解除该监听器。
EventEmitter.removeListener(event,listener) 移除指定事件的某个监听器,listener必须是该事件已经注册过的监听器。
EventEmitter.removeAllListeners([event])移除所有事件的所有监听器,如果指定event,则移除指定事件的所有监听器。
EventEmitter定义了一个特殊的事件 error,它包含了"错误"的语义,我们在遇到 异常的时候通常会发射 error 事件。
当 error被发射时,EventEmitter 规定如果没有响 应的监听器,Node.js 会把它当作异常,退出程序并打印调用栈。
四、函数
语法同javascript
1 2 3 4 5 6 7 8 9 | var http = require("http");
function onRequest(request, response) { response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end(); }
http.createServer(onRequest).listen(8888); |
五、路由
我们要为路由提供请求的URL和其他需要的GET及POST参数,随后路由需要根据这些数据来执行相应的代码,我们需要额外的Node.JS模块,它们分别是url和querystring模块。
现在我们可以来编写路由了,建立一个名为router.js的文件,添加以下内容:
1 2 3 4 5 | function route(pathname) { console.log("About to route a request for " + pathname); }
exports.route = route; |
然后我们来给onRequest()函数加上一些逻辑,用来找出浏览器请求的URL路径,并将路由函数作为参数传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | var http = require("http"); var url = require("url");
function start(route) { function onRequest(request, response) { var pathname = url.parse(request.url).pathname; console.log("Request for " + pathname + " received.");
route(pathname);
response.writeHead(200, {"Content-Type": "text/plain"}); response.write("Hello World"); response.end(); }
http.createServer(onRequest).listen(8888); console.log("Server has started."); }
exports.start = start; |
同时,我们会相应扩展index.js,使得路由函数可以被注入到服务器中:
varserver = require("./server"); var router =require("./router"); server.start(router.route);
在这里,我们传递的函数依旧什么也没做。
如果现在启动应用(node index.js,始终记得这个命令行),随后请求一个URL,你将会看到应用输出相应的信息,这表明我们的HTTP服务器已经在使用路由模块了,并会将请求的路径传递给路由:
1 2 3 | bash$ node index.js Request for /foo received. About to route a request for /foo |
六、全局对象
Node.js中的全局对象是global,所有全局变量(除了global本身以外)都是global对象的属性。
我们在Node.js中能够直接访问到对象通常都是global的属性,如console、process等。
1、process
process.argv是命令行参数数组,第一个元素是node,第二个元素是脚本文件名,从第三个元素开始每个元素是一个运行参数。
1 | console.log(process.argv); |
process.stdout是标准输出流,通常我们使用的 console.log()向标准输出打印 字符,而 process.stdout.write() 函数提供了更底层的接口。
process.stdin是标准输入流,初始时它是被暂停的,要想从标准输入读取数据,你必须恢复流,并手动编写流的事件响应函数。
1 2 3 4 | process.stdin.resume(); process.stdin.on('data', function(data) { process.stdout.write('read from console: ' + data.toString()); }); |
process.nextTick(callback)的功能是为事件循环设置一项任务,Node.js会在 下次事件循环调响应时调用 callback。
除此之外process还展示了process.platform、process.pid、process.execPath、process.memoryUsage()等方法,以及POSIX 进程信号响应机制。
详见http://nodejs.org/api/process.html
2、console
console用于提供控制台标准输出,它是由InternetExplorer的JScript引擎提供的调试 工具,后来逐渐成为浏览器的事实标准。
console.log接受若干个参数,如果只有一个参数,则输出这个参数的字符串形式。如果有多个参数,则以类似于C语言printf()命令的格式输出。
console.error():与console.log()用法相同,只是向标准错误流输出。
console.trace():向标准错误流输出当前的调用栈。
七、常用工具util
util是一个Node.js核心模块,提供常用函数的集合,用于弥补核心JavaScript的功能过于精简的不足。
util.inherits
util.inherits(constructor,superConstructor)是一个实现对象间原型继承的函数。
util.inspect
util.inspect(object,[showHidden],[depth],[colors])是一个将任意对象转换为字符串的方法,通常用于调试和错误输出。它至少接受一个参数object,即要转换的对象。
showHidden是一个可选参数,如果值为true,将会输出更多隐藏信息。
depth表示最大递归的层数,如果对象很复杂,你可以指定层数以控制输出信息的多 少。如果不指定depth,默认会递归2层,指定为null表示将不限递归层数完整遍历对象。如果color值为true,输出格式将会以ANSI颜色编码,通常用于在终端显示更漂亮的效果。
特别要指出的是,util.inspect并不会简单地直接把对象转换为字符串,即使该对 象定义了toString 方法也不会调用。
util.isArray(object)
如果给定的参数 "object"是一个数组返回true,否则返回false。
util.isRegExp(object)
如果给定的参数 "object"是一个正则表达式返回true,否则返回false。
util.isDate(object)
如果给定的参数 "object"是一个日期返回true,否则返回false。
util.isError(object)
如果给定的参数 "object"是一个错误对象返回true,否则返回false。
八、文件系统
Node.js文件系统封装在fs模块中
fs模块中所有的操作都提供了异步的和同步的两个版本,例如读取文件内容的函数有异步的 fs.readFile()和同步的fs.readFileSync()。
fs.readFile
1 | fs.readFile(filename,[encoding],[callback(err,data)]) |
- filename(必选),表示要读取的文件名。
- encoding(可选),表示文件的字符编码。
- callback 是回调函数,用于接收文件的内容。
如果不指 定 encoding,则callback 就是第二个参数。回调函数提供两个参数 err 和 data,err 表 示有没有错误发生,data 是文件内容。如果指定了encoding,data 是一个解析后的字符 串,否则 data 将会是以 Buffer 形式表示的二进制数据。
fs.open
fs.open(path, flags, [mode],[callback(err, fd)])是POSIX open函数的封装,与C 语言标准库中的fopen函数类似。它接受两个必选参数,path为文件的路径,flags 可以是以下值。
- r :以读取模式打开文件。
- r+ :以读写模式打开文件。
- w :以写入模式打开文件,如果文件不存在则创建。
- w+ :以读写模式打开文件,如果文件不存在则创建。
- a :以追加模式打开文件,如果文件不存在则创建。
- a+ :以读取追加模式打开文件,如果文件不存在则创建
fs.read
1 | fs.read(fd, buffer, offset, length, position, [callback(err, bytesRead, buffer)]) |
- fd: 读取数据并写入 buffer 指向的缓冲区对象。
- offset: 是buffer 的写入偏移量。
- length: 是要从文件中读取的字节数。
- position: 是文件读取的起始位置,如果 position 的值为 null,则会从当前文件指针的位置读取。
- callback:回调函数传递bytesRead 和 buffer,分别表示读取的字节数和缓冲区对象。
fs 模块函数表
九、GET/POST
1、GET
node.js中url模块中的parse函数可用来解析GET请求的url
1 2 3 4 5 6 7 8 | var http = require('http'); var url = require('url'); var util = require('util');
http.createServer(function(req, res){ res.writeHead(200, {'Content-Type': 'text/plain'}); res.end(util.inspect(url.parse(req.url, true))); }).listen(3000); |
2、POST
node.js默认是不会解析请求体的,当你需要的时候,需要手动来做。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | var http = require('http'); var querystring = require('querystring'); var util = require('util');
http.createServer(function(req, res){ var post = ''; //定义了一个post变量,用于暂存请求体的信息
req.on('data', function(chunk){ //通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中 post += chunk; });
req.on('end', function(){ //在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。 post = querystring.parse(post); res.end(util.inspect(post)); }); }).listen(3000); |