编写View
在编写View的时候,我们实际上是在编写HTML页。为了让页面看起来美观大方,使用一个现成的CSS框架是非常有必要的。我们用 Bootstrap这个CSS框架。从首页下载zip包后解压,我们把所有静态资源文件放到/static目录下:
view-koa/ | +- static/ | +- css/ <- 存放bootstrap.css等 | +- fonts/ <- 存放字体文件 | +- js/ <- 存放bootstrap.js等
这样我们在编写HTML的时候,可以直接用Bootstrap的CSS,像这样:
<link rel="stylesheet" href="/static/css/bootstrap.css">
现在,在使用MVC之前,第一个问题来了,如何处理静态文件?
我们把所有静态资源文件全部放入/static目录,目的就是能统一处理静态文件。在koa中,我们需要编写一个middleware,处理以/static/开头的URL。
编写middleware
我们来编写一个处理静态文件的middleware。编写middleware实际上一点也不复杂。我们先创建一个static-files.js的文件,编写一个能处理静态文件的middleware:
const path = require('path'); const mime = require('mime'); const fs = require('mz/fs'); // url: 类似 '/static/' // dir: 类似 __dirname + '/static' function staticFiles(url, dir) { return async (ctx, next) => { let rpath = ctx.request.path; // 判断是否以指定的url开头: if (rpath.startsWith(url)) { // 获取文件完整路径: let fp = path.join(dir, rpath.substring(url.length)); // 判断文件是否存在: if (await fs.exists(fp)) { // 查找文件的mime: ctx.response.type = mime.lookup(rpath); // 读取文件内容并赋值给response.body: ctx.response.body = await fs.readFile(fp); } else { // 文件不存在: ctx.response.status = 404; } } else { // 不是指定前缀的URL,继续处理下一个middleware: await next(); } }; } module.exports = staticFiles;
staticFiles是一个普通函数,它接收两个参数:URL前缀和一个目录,然后返回一个async函数。这个async函数会判断当前的URL是否以指定前缀开头,如果是,就把URL的路径视为文件,并发送文件内容。如果不是,这个async函数就不做任何事情,而是简单地调用await next()让下一个middleware去处理请求。
我们使用了一个mz的包,并通过require('mz/fs');导入。mz提供的API和Node.js的fs模块完全相同,但fs模块使用回调,而mz封装了fs对应的函数,并改为Promise。这样,我们就可以非常简单的用await调用mz的函数,而不需要任何回调。
所有的第三方包都可以通过npm官网搜索并查看其文档:
最后,这个middleware使用起来也很简单,在app.js里加一行代码:
let staticFiles = require('./static-files'); app.use(staticFiles('/static/', __dirname + '/static'));
注意:也可以去npm搜索能用于koa2的处理静态文件的包并直接使用。