Node.js创建第一个应用
Node.js开发的目的就是为了用JavaScript编写Web服务器程序, 在使用Node.js时,不仅仅是在实现一个应用,同时还实现了整个HTTP服务器。在创建Node.js第一个"Hello, World!"应用前,需先了解下Node.js应用是由哪几部分组成的:
- 引入require模块: 使用require指令载入Node.js模块
- 创建服务器: 服务器可以监听客户端的请求,类似于Apache、Nginx等HTTP服务器
- 接收请求与响应请求: 客户端可以使用浏览器或终端发送HTTP请求,服务器接收请求后返回响应数据
HTTP协议
要理解Web服务器程序的工作原理,首先,要对HTTP协议有基本的了解HTTP协议简介。
HTTP服务器
开发HTTP服务器程序, 从头处理TCP连接, 解析HTTP是不现实的. 这些工作实际上已经由Node.js自带的http模块帮我们完成了. 应用程序并不直接和HTTP协议打交道, 而是操作http
模块提供的request
和response
对象.
request
对象封装了HTTP请求,调用request
对象的属性和方法就可以得到所有HTTP请求的信息;
response
对象封装了HTTP响应,操作response
对象的方法,就可以把HTTP响应返回给浏览器;
用Node.js实现一个HTTP服务器程序。首先实现一个最简单的Web程序hello.js
,它对于所有请求,都返回Hello world!
:
步骤一、引入require模块
const http = require('http');
步骤二、创建服务器
使用http.createServer()方法创建服务器,并使用listen方法绑定8080端口. 函数通过request, response参数来接收和响应数据
const http = require('http');
http.createServer(function (request, response) {
// 发送 HTTP 头部
// HTTP 状态值: 200 : OK
// 内容类型: text/plain
response.writeHead(200, {'Content-Type': 'text/plain'});
// 发送响应数据 "Hello World"
response.end('Hello World!
');
}).listen(8080);
// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8080/');
'use strict';
// 导入http模块:
const http = require('http');
// 创建http server,并传入回调函数:
const server = http.createServer(function (request, response) {
// 回调函数接收request和response对象,
// 获得HTTP请求的method和url:
console.log(request.method + ': ' + request.url);
// 将HTTP响应200写入response, 同时设置Content-Type: text/html:
response.writeHead(200, {'Content-Type': 'text/html'});
// 将HTTP响应的HTML内容写入response:
response.end('<h1>Hello world!</h1>');
});
// 让服务器监听8080端口:
server.listen(8080);
console.log('Server is running at http://127.0.0.1:8080/');
'use strict';
// 导入http模块:
const http = require('http');
// 创建http server,并传入回调函数:
const server = http.createServer((request, response) => {
// 回调函数接收request和response对象,
// 获得HTTP请求的method和url:
console.log(request.method + ': ' + request.url);
// 将HTTP响应200写入response, 同时设置Content-Type: text/html:
response.writeHead(200, {'Content-Type': 'text/html'});
// 将HTTP响应的HTML内容写入response:
response.end('<h1>Hello world!</h1>');
});
// 让服务器监听8080端口:
server.listen(8080);
console.log('Server is running at http://127.0.0.1:8080/');
在命令行下运行该文件,可以看到以下输出:
$ node hello.js
Server is running at http://127.0.0.1:8080/
不要关闭命令提示符,直接打开浏览器输入http://localhost:8080
,即可看到服务器响应的内容:
同时,在命令提示符窗口,可以看到程序打印的请求消息:
GET: /
GET: /favicon.ico
文件服务器
继续扩展上面的Web程序, 可以设定一个目录,然后让Web程序变成一个文件服务器。要实现这一点,只需解析request.url
中的路径,然后在本地找到对应的文件,把文件内容发送出去就可以了。
解析URL需要用到Node.js提供的url
模块,它使用起来非常简单,通过parse()
将一个字符串解析为一个Url
对象:
'use strict';
const url = require('url');
console.log(url.parse('http://user:pass@host.com:8080/path/to/file?query=string#hash'));
结果如下:
Url {
protocol: 'http:',
slashes: true,
auth: 'user:pass',
host: 'host.com:8080',
port: '8080',
hostname: 'host.com',
hash: '#hash',
search: '?query=string',
query: 'query=string',
pathname: '/path/to/file',
path: '/path/to/file?query=string',
href: 'http://user:pass@host.com:8080/path/to/file?query=string#hash'
}
处理本地文件目录需要使用Node.js提供的path
模块,它可以方便地构造目录:
'use strict';
const path = require('path');
// 解析当前目录
const workDir = path.resolve('.');
// 组合完整的文件路径:当前目录 + 'static' + 'index.html'
const filePath = path.join(workDir, 'static', 'index.html');
console.log(workDir);
console.log(filePath);
// D:NodejsAppmiddlewareworkdir
// D:NodejsAppmiddlewareworkdirstaticindex.html
使用path
模块可以正确处理操作系统相关的文件路径。在Windows系统下,返回的路径类似于C:UsersUnitystaticindex.html
,这样,就不必关心怎么拼接路径了。最后,实现文件服务器file_server.js
'use strict';
const fs = require('fs');
const url = require('url');
const path = require('path');
const http = require('http');
// 从命令行参数获取root目录,默认是当前目录
const root = path.resolve(process.argv[2] || '.');
console.log(`Stctic root dir: ${root}`);
// 创建服务器
http.createServer((request, response) => {
// 获得URL的path,类似/css/bootstrap.css
const pathname = url.parse(request.url).pathname;
// 获得对应的本地文件路径,类似/src/css/bootstrap.css
const filepath = path.join(root, pathname);
// 获取文件状态
fs.stat(filepath, (err, stats) => {
if (!err && stats.isFile()) {
// 没有出错并且文件存在
console.log('200' + request.url);
// 发送200响应
response.writeHead(200);
// 将文件流导向response
fs.createReadStream(filepath).pipe(response);
} else {
// 出错或文件不存在
console.log('404' + request.url);
// 发送404
response.writeHead(404);
response.end('404 Not Found');
}
});
}).listen(8080);
console.log('Server is running at http://127.0.0.1:8080/');
没有必要手动读取文件内容, 由于response
对象本身是一个Writable Stream
,直接用pipe()
方法就实现了自动读取文件内容并输出到HTTP响应
在命令行运行node file_server.js
然后在浏览器中输入http://localhost:8080/index.html
只要当前目录下存在文件index.html
,服务器就可以把文件内容发送给浏览器。观察控制台输出
200 /index.html
200 /css/uikit.min.css
200 /js/jquery.min.js
200 /fonts/fontawesome-webfont.woff2
第一个请求是浏览器请求index.html
页面,后续请求是浏览器解析HTML后发送的其它资源请求
练习
在浏览器输入http://localhost:8080/
时,会返回404,原因是程序识别出HTTP请求的不是文件,而是目录。请修改file_server.js
,如果遇到请求的路径是目录,则自动在目录下依次搜索index.html
、default.html
,如果找到了,就返回HTML文件的内容。
参考源码
http服务器代码(含静态网站)