2.3 静态服务器
在早期的Web世界里,前端功能非常简单,就是单纯的页面展示,为了让这些静态页面通过互联网呈现给用户,需要将前端页面部署到一台服务器上,这就是静态服务器的概念。之前,很多人会用Nginx、Apache等部署一个静态服务器,部署前端项目后,就可以在浏览器访问了。其实静态服务器起到了提供一个读取静态文件(包括js、css、png等文件)、静态目录的作用。Koa也可以实现静态服务器的功能,本节带领读者部署一个介绍性的官网到Koa静态服务器上。
本节会介绍两种实现方式:一种是利用Koa中间件实现,这种方式比较简单,可以用现成的包;另一种是原生方式实现,这种方式虽然比较复杂,但是能够还原静态服务器的一些本质,利于理解原理。
现在要展示一个静态站点,最终实现的页面效果如图2-4所示。
图2-4 静态站点效果图
2.3.1 koa-static中间件的使用
静态服务器功能可以利用Koa的中间件koa-static实现,读者可以通过官方文档(https://github.com/koajs/static)进行了解。koa-static是一个npm包,在使用之前,需要先安装这个npm包,命令如下。
$ npm install --save koa-static
在分析代码之前,先展示一下项目组成,如图2-5所示。
图2-5 目录介绍
图2-5中,static目录下存放的是静态文件,index.js文件是Koa部分的逻辑实现。
index.js文件的代码如下。
const Koa = require('koa') const path = require('path') const static = require('koa-static') const app = new Koa() // 静态资源目录对于相对入口文件index.js的路径 const staticPath = './static' app.use(static( path.join( __dirname, staticPath) )) app.listen(4000, () => { console.log('server is running, port is 4000') })
2.3.2 如何实现一个静态服务器
如果不用Koa中间件,如何原生实现一个静态服务器呢?实现思路可以概括为通过请求的URL来读取静态文件。静态服务器通过请求把内容展示到页面上,只不过不同的静态资源,其mime type不同,能够对应起来即可。接下来看一下实现逻辑,代码如下。
const Koa = require('koa') const fs = require('fs') const path = require('path') // 设置一个mime map, 因为本项目只涉及3种类型, 所以这里只列3种 const MIMES_MAP = { 'css': 'text/css', 'html': 'text/html', 'jpg': 'image/jpeg' } const app = new Koa() // 静态资源目录对于相对入口文件index.js的路径 const staticPath = './static' // 解析资源类型 function parseMime( url ) { let extName = path.extname( url ) extName = extName ? extName.slice(1) : 'unknown' return MIMES_MAP[extName] } app.use( async ( ctx ) => { // 静态资源目录在本地的绝对路径 let fullStaticPath = path.join(__dirname, staticPath) // 获取静态资源内容, 有可能是文件内容、目录或404 let content = fs.readFileSync(path.join(fullStaticPath, ctx.url), 'binary' ) // 解析请求内容的类型 let mime = parseMime(ctx.url) // 如果有对应的文件类型, 就配置上下文的类型 if (mime) { ctx.type = mime } // 输出静态资源的内容 if ( mime && mime.indexOf('image/') >= 0 ) { // 如果是图片, 则用Node原生res, 输出二进制数据 ctx.res.writeHead(200) ctx.res.write(content, 'binary') ctx.res.end() } else { // 其他则输出文本 ctx.body = content } }) app.listen(4000, () => { console.log('server is running, port is 4000') })
通过一个map对静态资源类型和mime type做映射,再依据请求中的URL来读取对应的资源,再将其放回前端进行展示。
提示
在JavaScript中,要善于利用map做代码优化,比如if else、switch case的逻辑,多数情况可以用map来重写,完善后的代码会更加优雅且易于维护。