LoopBack 2 如何设置静态资源缓存时间

最近是在使用 LoopBack@^2.19.1 做一个页面,加载图片,发现每次都是请求新的图片 响应头:Cache-Control: public, max-age=0,于是查看文档研究了一下。

LooBack 文档对于这部分的介绍少得可怜。

疑问

1、首先看官方文档的介绍。 官方文档:loopback.io/doc/en/lb2/...

json 复制代码
// server/middleware.json
// 关键配置
// client 目录就是静态资源目录
{
    "files": {
        "loopback#static": {
          "params": "$!../client"
        }
    }
}

如果想设置资源的可以被缓存的最长时间(即设置响应头:Cache-Control: max-age=3600),文档没有说明,该怎么办呢?

我是用了笨办法:看源码。

2、首先理清楚依赖:loopback@^2.19.1 -> express@^4.16.2

json 复制代码
// node_modules\loopback\package.json
{
  "name": "loopback",
  "version": "2.42.0",
  "engines": {
    "node": ">=4.0.0"
  },
  "dependencies": {
    "express": "^4.16.2"
  }
}

3、看 Loopback 源码的入口和项目目录结构。

重点看 index.jsserver/middleware/static.js

vbnet 复制代码
│  index.js
│  package.json
│
├─common
│  └─models
│          access-token.js
│          access-token.json
│          acl.js
│          acl.json
│          application.js
│          application.json
│          change.js
│          change.json
│          checkpoint.js
│          checkpoint.json
│          email.js
│          email.json
│          key-value-model.js
│          key-value-model.json
│          README.md
│          role-mapping.js
│          role-mapping.json
│          role.js
│          role.json
│          scope.js
│          scope.json
│          user.js
│          user.json
├─lib
│  │  access-context.js
│  │  application.js
│  │  browser-express.js
│  │  builtin-models.js
│  │  current-context.js
│  │  express-middleware.js
│  │  loopback.js
│  │  model.js
│  │  persisted-model.js
│  │  registry.js
│  │  runtime.js
│  │  server-app.js
│  │  utils.js
│  │
│  └─connectors
│          base-connector.js
│          mail.js
│          memory.js
│
├─server
│  └─middleware
│          context.js
│          error-handler.js
│          favicon.js
│          rest.js
│          static.js
│          status.js
│          token.js
│          url-not-found.js
│
└─templates
        reset-form.ejs
        verify.ejs

4、关键字搜索 static 发现 node_modules\loopback\server\middleware\static.js

js 复制代码
// 省略文件版本信息

/**
 * Serve static assets of a LoopBack application.
 *
 * @param {string} root The root directory from which the static assets are to
 * be served.
 * @param {object} options Refer to
 *   [express documentation](http://expressjs.com/4x/api.html#express.static)
 *   for the full list of available options.
 * @header loopback.static(root, [options])
 */
module.exports = require('express').static;

从注释可以看出,第一个参数(root)是静态目录的文件夹。第二个参数是可选的,它是 object,查看 express static 文档:expressjs.com/4x/api.html...

5、尝试设置 1 -> 不生效。

json 复制代码
// server/middlewar.json
{
"files": {
    "loopback#static": {
      "params": "$!../client",
      "maxAge": "1h"
    }
  }
}

6、尝试设置 2 -> 不生效。

json 复制代码
// server/middlewar.json
{
"files": {
    "loopback#static": {
      "params": "$!../client",
      "options": {"maxAge": "1h"}
    }
  }
}

7、尝试设置 3 -> 生效。

json 复制代码
// server/middlewar.json
{
"files": {
    "loopback#static": {
      "params": ["$!../client", {"maxAge": "1h"}]
    }
  }
}

继续深入探索

别问我为什么要尝试,因为那时还没看懂 LoopBack 2 是怎样初始化中间件的。 今天看懂了。

1、开启 debug

bash 复制代码
DEBUG=loopback node .

参考文档:loopback.io/doc/en/lb2/...

2、看日志

swift 复制代码
loopback:boot:executor Configuring middleware "xxx\\node_modules\\loopback"#static

3、打开项目 loopback-boot 项目搜索 loopback:boot:executor

arduino 复制代码
// node_modules\loopback-boot\lib\executor.js

4、搜索 Configuring middleware

ini 复制代码
function setupMiddleware(app, instructions) {
  if (!instructions.middleware) {
    // the browserified client does not support middleware
    return;
  }

  // Phases can be empty
  var phases = instructions.middleware.phases || [];
  assert(Array.isArray(phases),
    g.f('{{instructions.middleware.phases}} must be an {{array}}'));

  var middleware = instructions.middleware.middleware;
  assert(Array.isArray(middleware),
    'instructions.middleware.middleware must be an object');

  debug('Defining middleware phases %j', phases);
  app.defineMiddlewarePhases(phases);

  middleware.forEach(function(data) {
    debug('Configuring middleware %j%s', data.sourceFile,
        data.fragment ? ('#' + data.fragment) : '');
    var factory = requireNodeOrEsModule(data.sourceFile);
    if (data.fragment) {
      factory = factory[data.fragment].bind(factory);
    }
    assert(typeof factory === 'function',
      'Middleware factory must be a function');
    var opts = {
      useEnvVars: true,
    };
    data.config = getUpdatedConfigObject(app, data.config, opts);
    app.middlewareFromConfig(factory, data.config);
  });
}

5、打开项目 loopback 搜索 middlewareFromConfig

js 复制代码
node_modules\loopback\lib\server-app.js

/**
 * Register a middleware using a factory function and a JSON config.
 *
 * **Example**
 *
 * ```js
 * app.middlewareFromConfig(compression, {
 *   enabled: true,
 *   phase: 'initial',
 *   params: {
 *     threshold: 128
 *   }
 * });
 * ```
 *
 * @param {function} factory The factory function creating a middleware handler.
 *   Typically a result of `require()` call, e.g. `require('compression')`.
 * @options {Object} config The configuration.
 * @property {String} phase The phase to register the middleware in.
 * @property {Boolean} [enabled] Whether the middleware is enabled.
 *   Default: `true`.
 * @property {Array|*} [params] The arguments to pass to the factory
 *   function. Either an array of arguments,
 *   or the value of the first argument when the factory expects
 *   a single argument only.
 * @property {Array|string|RegExp} [paths] Optional list of paths limiting
 *   the scope of the middleware.
 *
 * @returns {object} this (fluent API)
 *
 * @header app.middlewareFromConfig(factory, config)
 */
proto.middlewareFromConfig = function(factory, config) {
  assert(typeof factory === 'function', '"factory" must be a function');
  assert(typeof config === 'object', '"config" must be an object');
  assert(typeof config.phase === 'string' && config.phase,
    '"config.phase" must be a non-empty string');

  if (config.enabled === false)
    return;

  var params = config.params;
  if (params === undefined) {
    params = [];
  } else if (!Array.isArray(params)) {
    params = [params];
  }

  var handler = factory.apply(null, params);
  
  // 省略了一些代码 

  return this;
};

6、然后看到

js 复制代码
var params = config.params;
if (params === undefined) {
    params = [];
} else if (!Array.isArray(params)) {
    params = [params];
}

var handler = factory.apply(null, params);

然后就可以解释为什么要配置成

json 复制代码
// server/middlewar.json
{
  "files": {
    "loopback#static": {
      "params": ["$!../client", {"maxAge": "30d"}]
    }
  }
}
相关推荐
snow@li3 小时前
d3.js:学习积累
开发语言·前端·javascript
vincention3 小时前
JavaScript 中 this 指向完全指南
前端
qyresearch_4 小时前
射频前端MMIC:5G时代的技术引擎与市场机遇
前端·5g
天蓝色的鱼鱼4 小时前
Next.js 渲染模式全解析:如何正确选择客户端与服务端渲染
前端·react.js·next.js
一枚前端小能手4 小时前
🚀 巨型列表渲染卡顿?这几个优化技巧让你的页面丝滑如德芙
前端·javascript
酷柚易汛智推官4 小时前
Electron技术深度解析:跨平台桌面开发的利器与挑战
前端·javascript·electron
llz_1124 小时前
第五周作业(JavaScript)
开发语言·前端·javascript
yannick_liu4 小时前
nuxt4 + nuxt-swiper实现官网全屏播放
前端
苏打水com4 小时前
JS基础事件处理与CSS常用属性全解析(附实战示例)
前端