使用Node
进行网络开发
用户在浏览器中输入网址 --> 获得网页的过程经历了几个步骤:
通过浏览器发送一个请求到服务器(期间经历的DNS解析、TCP3次握手连接)
服务器分析、处理用户的请求,并生产请求的内容,然后发送给浏览器
浏览器解析服务发送回的数据,生产网页
服务器
在HTTP协议中的服务器指:监听客户端的请求,并且根据请求的内容进行相应处理,返回响应给客户端。
Node
中可以利用http
模块进行Web服务器的搭建。
http
模块
http
模块不是Node
的核心模块,需要利用require()
加载-
使用
http.createServer()
方法创建一个http
服务器,返回一个http
服务器对象利用服务器对象进行开发
接收的回调函数是监听到客户端请求时的回调函数
-
server.listen()
方法可以开启Web服务,监听某台主机的某个端口参数是
(port, hostname, backlog, callback)
-
port
是监听主机的端口号;hostname
是监听主机的IP地址;callback
是服务器成功开启后的回调函数(开启服务器后,再连接数据库)// 搭建一个HTTP服务器,用于处理用户发送的http请求 // http模块不是核心模块,需要require()导入 var http = require('http'); // http模块的createServer()方法可以返回一个标准http服务器对象 // 通过服务器对象来进行开发 // callback是监听到客户端连接的回调函数 var server = http.createServer(callback); // 服务器监听某个网卡上的某个端口,开启服务 // listen(port, hostname, backlog, callback) // port是监听的端口,hostname是监听主机的ip地址,callback是服务器开启成功后的回调函数 // 服务器开启失败时触发error事件 server.on('error', function (err) { console.log(err); }) // listening事件在服务器开启成功时触发 server.on('listening', function () { console.log('listening...8080'); }) // 监听来自客户端的请求事件,在接收到请求时触发 server.on('request', function () { console.log("there is a request"); }) server.listen(8080, 'localhost');
主要的事件
服务器开启失败的事件
error
的监听:server.on('errro', function(err) {})
服务器开启成功的事件
listening
的监听:server.on('listening', function(err) {})
,可以写在server.listen()
方法的回调函数中服务器接收到请求的事件
request
的监听:server.on('request', function(err, req, res) {})
,可以写在http.createServer()
方法的回调函数中
参数对象
request
事件接收两个参数:
-
request
对象:提供客户端请求相关数据的对象,是http.IncomingMessage
类的一个实例,有对应的属性与方法httpVersion
属性:使用的HTTP协议版本header
属性:请求头中相关的数据url
属性:method
属性:请求的方式...
-
response
对象:服务端向客户端发送的响应数据对象,是http.ServerResponse
类的一个实例write(chunk, [encoding])
:发送一个数据库到响应的正文(网页的内容数据)中,需要在发送完成后调用res.end()
方法end(chunk, [encoding], [callback])
:在通过write()
方法发送完所有正文和头信息后,需要res.end()
告诉服务器数据全部发送完成。每个响应都必须调用res.end()
方法,并且在最后调用。
如果指定了chunk
,则它等同于调用response.write(chunk, encoding)
之后调用response.end(callback)
writeHeader(statusCode [, statusMessage] [, headers])
:写入头信息,在res.write()
前调用,并且一次响应中只能调用一次,头信息写在一个对象中-
statusCode
属性和setHeader()
方法可以组合实现writeHeader()
的功能server.on('request', function (req, res) { console.log("there is a request"); var chunk = '<h1>hello world</h1>'; // Buffer.byteLength(chunk)以字节为单位,告诉浏览器以纯文本解析传回的数据 res.writeHeader(200, 'OK', {'Content-type': 'text/plain', 'Content-length': Buffer.byteLength(chunk)}); res.end(chunk, 'utf-8'); })
url
处理
根据用户请求的path
返回不同的数据,使用req.url
可以获取path
信息。
req.url
中?
后面的部分叫做query
。Node
下的url
模块可以处理请求的中的req.url
-
使用
switch
结构,为不同的pathname
划分不同的逻辑处理方式server.on('request', function (req, res) { console.log(req.url); // req.url获取请求的路径path信息 var urlStr = url.parse(req.url); switch(urlStr.pathname) { case '/': // 首页 res.writeHeader(200, 'OK', {'Content-type': 'text/plain'}); res.end('<h1>首页</h1>', 'utf-8'); break; case '/users': // 用户页 res.writeHeader(200, 'OK', {'Content-type': 'text/plain'}); res.end('<h1>用户页</h1>', 'utf-8'); break; default : // 不存在 res.writeHeader(404, 'Not Found', {'Content-type': 'text/plain'}); res.end('<h1>出错</h1>', 'utf-8'); break; } })
使用fs
模块实现行为与表现分离
根据用户不同访问的不同路径,执行不同操作,读取不同页面
server.on('request', function (req, res) {
console.log(req.url);
var urlStr = url.parse(req.url);
switch(urlStr.pathname) {
case '/': // 首页
sendData(htmlDir + '/index.html', req, res); // 请求不同的路径,读取不同的页面返回给客户端
break;
case '/users': // 用户页
sendData(htmlDir + '/user.html', req, res);
break;
default : // 不存在
sendData(htmlDir + '/404.html', req, res);
break;
}
});
// 每次请求都读取静态页面,再输出。 fs.readFile()方法封装了fs.open()、fs.read()和fs.close()方法
// fs.readFile()返回值是原始的buffer对象
function sendData(file, req, res) {
fs.readFile(file, function (err, data) {
if(err) {
res.writeHeader(404, "Not Found", {'Content-Type': 'text/html'});
res.end('Not Found');
} else {
res.writeHeader(200, "OK", {'Content-Type': 'text/html'});
res.end(data);
}
});
}
处理GET
与POST
请求提交的数据
通过
GET
方法传递的数据可以使用url.parse(req.url).query
获取到GET
请求提交的数据,使用querystring
内置模块(无需加载)来解析GET
请求提交的数据绑定在url
中,使用querystring.parse()
方法解析url
的query
属性便可以得到GET
请求提交的数据-
POST
请求提交的数据在HTTP的Body
中,服务器接收到的是数据流(因为POST
请求提交的数据量较大,需要从缓冲区区读取chunk
)利用
request
对象的data
事件,触发回调函数接收所有提交的数据。可以将其拼接到一个字符串上-
接收完所有数据后触发
end
事件,此时才可以使用querystring.parse()
解析接收到的所有数据var http = require('http'); var url = require('url'); var fs = require('fs'); var querystring = require('querystring'); var server = http.createServer(); var htmlDir = __dirname + '/html/'; // 使用fs读取html目录下的文件 server.on('request', function (req, res) { var urlStr = url.parse(req.url); switch(urlStr.pathname) { case '/': // 首页 sendData(htmlDir + '/index.html', req, res); break; case '/users': // 用户页 sendData(htmlDir + '/user.html', req, res); break; // 增加登录页面的路由 case '/login': // 用户页 sendData(htmlDir + '/login.html', req, res); break; // 增加登录页面提交数据的处理 case '/login/check': // 用户页 if(req.method.toUpperCase() === 'GET') { console.log(querystring.parse(urlStr.query)); // 使用querystring.parse()将传递的数据解析为一个对象 } if(req.method.toUpperCase() === 'POST') { var str = ''; // 用来接收POST传递来的数据 req.on('data', function (chunk) { str += chunk; }) req.on('end', function () { console.log(querystring.parse(str)); }) } break; default : // 不存在 sendData(htmlDir + '/404.html', req, res); break; } }); // 每次请求都读取静态页面,再输出。 fs.readFile()方法封装了fs.open()、fs.read()和fs.close()方法 function sendData(file, req, res) { fs.readFile(file, function (err, data) { if(err) { res.writeHeader(404, "Not Found", {'Content-Type': 'text/html'}); res.end('Not Found'); } else { res.writeHeader(200, "OK", {'Content-Type': 'text/html'}); res.end(data); } }); } server.listen(8080, 'localhost');
常识
http
模块的服务器默认返回的数据类型是text/html
http
模块中的http.STATUS_CODES
属性包含所有的状态码及其描述信息
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。