brunoyang / blog

134 stars 13 forks source link

static file & koa-static #15

Open brunoyang opened 8 years ago

brunoyang commented 8 years ago

用户访问我们的网站,得到的结果有两种,想看的和不想看的。

不想看的分两种,网站报错和地址输错。

想看的也分两种,动态生成和静态存在。今天,我们就来聊聊静态文件。

所谓静态文件

所谓的静态文件,就是静态的,static的文件,无需经过查找数据库、模板渲染等步骤(以上步骤为充分不必要)就可以直接给用户看的,如js、css文件,图片等。

一般来说,访问静态文件的url和其本身的文件路径是一样,如 http://a.com/public/img/a.png, 那目录下就会有个public文件夹。这是因为静态文件数量很可能非常庞大,不能给每个文件都加上路由,所以其文件路径就是url。

每个http响应头里都有Content-Type字段,该字段告诉浏览器返回的文件是什么类型的,便于浏览器处理。如一个html文件的Content-Type是text/html,而一般的文本文件Content-Type是text/plain,当把html文件的Content-Type改成text/plain,浏览器就不会解析html文件,而是直接输出html代码。我们可以通过文件的后缀识别该文件的MIME。

koa-static

有了上面的知识,我们再来看koa-static。基本用法如下代码:

'use strict';

const app = require('koa')();
const server = require('koa-static');

const opts = {
  maxage: 1000 * 60 * 60 * 24 * 365, // 1年,默认为0
  hidden: false, // 能否返回隐藏文件(以`.`打头),默认false不返回
  index: 'index.js', // 默认文件名
  defer: true, // 在yield* next之后返回静态文件,默认在之前
  gzip: true 
  // 允许传输gzip,如静态文件夹下有两个文件,index.js和index.js.gz,
  // 会优先传输index.js.gz,默认开启
};

app.use(server('/public', opts));

koa-static所做的,仅仅是简单地处理选项,真正干事的是koa-send模块,我们再来看看这个模块。

前面一段是选项处理,略过,看如下代码

if (encoding === 'gzip' && gzip && (yield fs.exists(path + '.gz'))) {
  path = path + '.gz';
  ctx.set('Content-Encoding', 'gzip');
  ctx.res.removeHeader('Content-Length');
}

如果开启了gzip选项,就会优先传输.gz文件。

if (stats.isDirectory()) {
  if (format && index) {
    path += '/' + index;
    stats = yield fs.stat(path);
  } else {
    return;
  }
}

若为目录,并且找不到index配置项的文件,直接return,如无意外就是404,不过这样情况是应该是403。另外,是否为隐藏文件的判断居然只是根据文件名前的.,完全不考虑windows机器。勇敢的少年快去提pr吧。

核心代码就是下面的几行

ctx.set('Content-Length', stats.size);
if (!ctx.response.get('Last-Modified')) {
  ctx.set('Last-Modified', stats.mtime.toUTCString());
}
if (!ctx.response.get('Cache-Control')) {
  ctx.set('Cache-Control', 'max-age=' + (maxage / 1000 | 0));
}
ctx.type = type(path);
ctx.body = fs.createReadStream(path);
DarkFlame commented 7 years ago

好 !!

zaleGZL commented 6 years ago

我使用了koa中的koa-static中间件来处理静态资源,可是为什么第二次请求相同的静态资源(资源未修改), 服务器返回的状态码不是304而是200?last-modified 和 if-modified-since 都正常发送了,我试了一下express就正常返回304,请问是设置的问题还是?

src

network