nodejs 学习笔记(四)—— 搭建静态Web服务器
在学习笔记(一)里我们已经搭建过一个最简单的服务器,但这个服务器只能返回简单的信息。学习了fs模块,可以利用它实现更复杂的功能。
现在有这样一个需求,在地址栏里输入网址,需要服务器返回相应的html页面,以及页面里依赖的css、js、json等格式的文件。这里的重点是根据不同的路径用fs模块读取相应的文件返回给浏览器,并且根据文件类型设置不同的 ContentType。
准备一个mime.json文件,里面存储了后缀名和ContentType的映射关系,再创建一个getMime方法,用来返回后缀对应的ContentType
// 包装成Promise用来实现同步方法 function getMime(extname) { return new Promise((resolve, reject) => { fs.readFile('./data/mime.json', (err, data) => { if (err) { reject(err) return } let mimeObj = JSON.parse(data.toString()) resolve(mimeObj[extname]) }) }) }
接着在app.js里处理请求,借用了path模块的extname方法获取后缀
const http = require('http') const fs = require('fs') const getMime = require('./module/common.js') const path = require('path') const server = http.createServer((req, res) => { const url = new URL(req.url, 'http://127.0.0.1:3000') // 获取路径 let pathname = url.pathname // 获取后缀 let extname = path.extname(pathname) // 过滤掉图标 if (pathname != 'favicon.ico') { // 默认跳转到index.html pathname = pathname ? pathname : 'index.html' fs.readFile('./static' + pathname, async (err, data) => { if (err) { // 页面不存在返回404 res.setHeader('ContentType', 'text/html') res.end('404') return } res.statusCode = 200; // getMime方法——通过后缀获取对应的ContentType res.setHeader('ContentType', await getMime(extname)) res.end(data) }) } }) server.listen(3000, () => { console.log('服务器运行在 http://localhost:3000') })
目录结构:
当我们访问 http://localhost:3000 时,默认请求index.html,浏览器解析index.html时遇到<script>、<link>标签则继续向服务器请求js、css文件,服务器根据后缀名设置不同的 ContentType 并返回相应数据。
接下来我们把上面的处理逻辑抽离出来封装成一个方法放在新建的 routes.js 文件里:
// 改成同步方式 function getMime(extname) { let data = fs.readFileSync('./data/mime.json') let mimeObj = JSON.parse(data.toString()) console.log(mimeObj[extname]) return mimeObj[extname] } exports.static = function (req, res, staticPath) { const url = new URL(req.url, 'http://127.0.0.1:3000') // 获取路径 let pathname = url.pathname // 过滤掉图标 if (pathname != 'favicon.ico') { // 默认跳转到index.html pathname = pathname === '/' ? '/index.html' : pathname // 获取后缀 let extname = path.extname(pathname) try { let data = fs.readFileSync('./' + staticPath + pathname)
if (err) {
// 页面不存在返回404
res.setHeader('ContentType', 'text/html')
res.end('404')
return
}
res.statusCode = 200;
// getMime方法——通过后缀获取对应的ContentType
res.setHeader('ContentType', await getMime(extname))
res.end(data)
} catch (error) { } } }
然后在app.js引入 static 方法
const http = require('http') const routes = require('./module/routes') const server = http.createServer((req, res) => { // 如果是访问静态资源,指向static目录下的文件 routes.static(req, res, 'static') }) server.listen(3000, () => { console.log('服务器运行在 http://localhost:3000') })
这样,所有请求都会先由 static 方法 处理。在实际应用中,有些资源是保存在服务器上不会变化的,称为静态资源,在本例中指的是index.html,css、js、图片等文件。通过这样一个静态web服务器我们就能够处理静态资源了。
还有一些根据请求可以动态改变文件内容的称为动态资源,借助模板引擎可以将静态模板与动态数据结合起来生成动态文件,我们下节再讨论。