文件路径示意:
C:\Users\Administrator\我的文档\HBuilderProject\httpServer
httpServer:
│ app.js
│
└─HS\
│ httpServer.html // 主页面
│
├─css
│ test.css
│
├─imgs
│ img.jpg
│
└─js
test.js
静态资源内容:
httpServer.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<link rel="stylesheet" href="css/test.css">
</head>
<body>
<h1>Hello World!</h1>
<img src="imgs/img.jpg">
</body>
<script src="js/test.js"></script>
</html>
</html>
test.css
h1 {
color: skyblue;
}
test.js
alert("sss");
img
一张图
静态服务器实现大致思路:
浏览器发送URL,服务端解析URL,对应到硬盘上的文件。如果文件存在,返回200状态码,并发送文件到浏览器端;如果文件不存在,返回404状态码,发送一个404的文件到浏览器端。
app.js
var http = require('http')
var path = require('path')
var fs = require('fs')
var url = require('url')
function staticRoot(staticPath, req, res) {
console.log("staticPath: " + staticPath);
console.log("req.url: " + req.url); // 查看请求URL
var pathObj = url.parse(req.url, true);
console.log(pathObj); // 使用URL模块的功能函数解析请求URL,得到相关对象
if (pathObj.pathname === '/') {
pathObj.pathname += 'httpServer.html'
}
var filePath = path.join(staticPath, pathObj.pathname); // 拼装为各资源文件绝对路径
// c:\Users\Administrator\我的文档\HBuilderProject\httpServer\HS + ['httpServer.html','/css/test.css','/imgs/img.jpg','/js/test.js']
console.log("filePath: " + filePath);
fs.readFile(filePath, 'binary', function (err, fileContent) {
if (err) {
console.log('404')
res.writeHead(404, 'not found')
res.end('<h1>404 Not Found</h1>')
} else {
console.log('ok');
res.writeHead(200, 'OK');
res.write(fileContent, 'binary');
res.end();
}
});
console.log("\n");
}
var server = http.createServer(function (req, res) {
staticRoot(path.join(__dirname, 'HS'), req, res); // 将其组装成资源文件夹路径
// c:\Users\Administrator\我的文档\HBuilderProject\httpServer\ + HS
})
server.listen(8080);
console.log('visit http://localhost:8080');
访问localhost:8080
,将会进入createServer函数,参数req res
包括了浏览器的请求信息和响应信息(head),我们用一个staticRoot函数来接受并处理后续内容。
参数__dirname
为app.js所在绝对路径的文件夹。
c:\Users\Administrator\我的文档\HBuilderProject\httpServer
使用join()方法,拼接静态资源内容所在文件夹。
// c:\Users\Administrator\我的文档\HBuilderProject\httpServer\HS
此时,本地服务器便可根据绝对路径找到相关静态文件,发送出去。
接下来需要解析请求URL。
console.log("req.url: " + req.url);
在我们传入staticRoot函数中的req对象包含了许多请求信息,如User-Agent、cookie、accept、host、method.........
url.parse()可以将一个完整的URL地址,分为很多部分,常用的有:host、port、pathname、path、query。
var pathObj = url.parse(req.url, true);
我们可以从req
对象里得到用户的请求URL,其实就是文件的路径。
每一次请求的pathObj如下:
var filePath = path.join(staticPath, pathObj.pathname);
拼接为绝对路径。
请求URL:
c:\Users\Administrator\我的文档\HBuilderProject\httpServer\HS\httpServer.html
c:\Users\Administrator\我的文档\HBuilderProject\httpServer\HS\css\test.css
c:\Users\Administrator\我的文档\HBuilderProject\httpServer\HS\imgs\img.jpg
c:\Users\Administrator\我的文档\HBuilderProject\httpServer\HS\js\test.js
进入下面的函数。
fs.readFile(filePath, 'binary', function (err, fileContent) { // 这个函数只执行了一次
test++;
if (err) {
console.log('404')
res.writeHead(404, 'not found')
res.end('<h1>404 Not Found</h1>')
} else {
console.log('ok');
res.writeHead(200, 'OK');
res.write(fileContent, 'binary');
res.end();
}
});
关于fs模块:
异步读取时,传入的回调函数接收两个参数,当正常读取时,err
参数为null
,fileContent
参数为读取到的String
。当读取发生错误时,err
参数代表一个错误对象,fileContent
为undefined
。这也是Node.js标准的回调函数:第一个参数代表错误信息,第二个参数代表结果。
res.writeHead()
向请求的客户端发送响应头。
该函数在一个请求内最多只能调用一次,如果不调用,则会自动生成一个响应头。
response.writeHead(statusCode, [reasonPhrase], [headers])
// statusCode:响应头的状态码,如:200、404等
// reasonPhase:[可选],用于简单说明的字符串。比如:“服务器因为维护暂时无法正常访问....”
// headers:类似关联数组的对象,表示响应头的每个属性
res.write()
向请求的客户端发送响应内容。
在 response.end() 之前,response.write() 可以被执行多次。
response.write(chunk, [encoding])
// chunk:一个buffer 或 字符串,表示发送的内容
// encoding:如果chunk是字符串,就需要指定encoding来说明它的编码方式,默认utf-8
res.end()
结束响应,告诉客户端所有消息已经发送。当所有要返回的内容发送完毕时,该函数必须被调用一次。
如何不调用该函数,客户端将永远处于等待状态。
response.end([data], [encoding])
// data:end()执行完毕后要输出的字符,如果指定了 data 的值,那就意味着在执行完 response.end() 之后,会接着执行一条 response.write(data , encoding);
// encoding:对应data的字符编码
所有资源读取返回客户端后,将先弹出对话框,然后显示页面。