静态资源服务器
问题分析
由于我们无法事先得知一个.html文件中会引用多少个静态资源(.png, .css, .js…),所以,我们不能像处理某个页面一样去处理它们。
我们的解决办法是:
- 把所有的静态资源(.html,.png,.css,.js)全放在一个指定的目录里;
- 收到用户的请求之后,去指定的目录下去找对应的文件
- 找到,把内容读出来返回给用户。
- 找不到,报404。
1. 准备资源:
- 准备一个名为public目录,如下:
|-public
|-public/index.html
|-public/stye.css
|-public/1.png
|-public/js/index.js
|-server.js
在上面的目录结构中,我们把所有的静态资源全放在public下面,然后使用server.js来启动web服务器。
- 在index.html里引入img:1.png、css:stye.css、js:index.js文件
2. 设置
-
创建http服务器
// 1.导入核心模块http const http = require('http') // 2.创建服务 const server = http.createServer((req, res) => { res.end('ok') }) // 3.启动服务 server.listen(8072) //回调可写可不写
-
req.url
// 1.导入核心模块 http/path const http = require('http') const path = require('path') // 2.创建服务 const server = http.createServer((req, res) => { // 如果req.url要访问的文件在public能找到,就读出来,返回 const filePath = path.join(__dirname, 'public', req.url) res.end(filePath) }) // 3.启动服务 server.listen(8072) //回调可写可不写
-
思路分析
// 思路: // if (filePath存在) { // 读出来返回 // } else { // 返回404 // } //代码实现: //导入fs核心模块 const fs = require('fs') //读入文件 fs.readFile(filePath, (err, data) => { //判断 if (err) { //如果读入有错误,404,返回not found res.statusCode = 404 res.end('not found') } else { //没有错误则返回数据 res.end(data) } })
3. 优化完善效果
-
省略地址栏index.html
-
如果直接
http://localhost:8072
==> req.url就是 /,这时,希望他去加载 /index.htmlconst url = req.url === '/' ? '/index.html' : req.url //这样 req.url的值就变成了: const filePath = path.join(__dirname, 'public', url)
-
-
设置响应头中的content-type
-
现在所求资源都没有设置content-type,都是浏览器自己猜出来,最好是根据不同后缀名,给请求设置content-type,明确告诉浏览器本质请求应该怎么处理,不要自己猜
// res.setHeader('content-type', '这个值是要根据不同文件类型去设置') // 如果按照正常思维,应该这样写: // .png --> 'image/png' // .html --> 'text/html;charset=utf8' // .js --> 'application/javascript;charset=utf8' // .css --> 'text/css;charset=utf8' // 获取后缀名 const extName = path.extname(filePath) if(extName === '.png') { res.setHeader('content-type', 'image/png') }else if(extName === '.html') { res.setHeader('content-type', 'text/html;charset=utf8') }else if(extName === '.js') { res.setHeader('content-type', 'application/javascript;charset=utf8') }else if(extName === '.css') { res.setHeader('content-type', 'text/css;charset=utf8') }
-
但是这种办法如果添加别的文件类型,会很繁琐,所以我们可以利用创建对象,优化一下方法
//创建一个对象,把这些信息放进去 const obj = { ".png":"image/png", ".jpg":"image/jpg", ".html":"text/html;charset=utf8", ".js":"application/javascript;charset=utf8", ".css":"text/css;charset=utf8" } //这样那对繁琐的代码可以简化为: if(obj[extName]) { res.setHeader('content-type', obj[extName]) } //这样加新的文件类型就会很方便
- 当我们的值是一一对应的时候,就可以通过对象来优化代码,这个方法叫
策略模式
- 当我们的值是一一对应的时候,就可以通过对象来优化代码,这个方法叫
-
4. 整体代码
// 目标
// 完成server.js代码
// 1.导入核心模块http/path/fs
const http = require('http')
const path = require('path')
const fs = require('fs')
// “策略模式”
//创建一个对象,把这些信息放进去
const obj = {
".png": "image/png",
".jpg": "image/jpg",
".html": "text/html;charset=utf8",
".js": "application/javascript;charset=utf8",
".css": "text/css;charset=utf8"
}
// 2.创建服务
const server = http.createServer((req, res) => {
// 如果直接http://localhost:8072==>req.url就是/,这时,希望他去加载/index.html
const url = req.url === '/' ? '/index.html' : req.url
// 如果req.url要访问的文件在public能找到,就读出来,返回
const filePath = path.join(__dirname, 'public', url)
// 思路:
// if (filePath存在) {
// 读出来返回
// } else {
// 返回404
// }
//读入文件
fs.readFile(filePath, (err, data) => {
//判断
if (err) {
//如果读入有错误,404,返回not found
res.statusCode = 404
res.end('not found')
} else {
// res.setHeader('content-type', '这个值是要根据不同文件类型去设置'),如果按照正常思维,应该这样写:
// .png --> 'image/png'
// .html --> 'text/html;charset=utf8'
// .js --> 'application/javascript;charset=utf8'
// .css --> 'text/css;charset=utf8'
// 获取后缀名
// const extName = path.extname(filePath)
// if (extName === '.png') {
// res.setHeader('content-type', 'image/png')
// } else if (extName === '.html') {
// res.setHeader('content-type', 'text/html;charset=utf8')
// } else if (extName === '.js') {
// res.setHeader('content-type', 'application/javascript;charset=utf8')
// } else if (extName === '.css') {
// res.setHeader('content-type', 'text/css;charset=utf8')
// }
//这样那对繁琐的代码可以简化为:
const extName = path.extname(filePath)
console.log('本次请求的资源', extName, filePath)
if (obj[extName]) {
res.setHeader('content-type', obj[extName])
}
//这样加新的文件类型就会很方便
//没有错误则返回数据
res.end(data)
}
})
// res.end('ok')
})
// 3.启动服务
server.listen(8077) //回调可写可不写