静态内容

该教程适用于 hapi v17版本

在构建任意一个 web 应用时,不可避免的需要从磁盘提供一些静态文件。有一个名为 inert 的 hapi 插件可以完成这个操作。

首先你需要安装它,并且将 inert 作为依赖添加到你的项目中:

npm install —save inert

h.file(path, [options])

首先我们看如何使用 h.file() 方法:

  1. const start = async () => {
  2.  
  3. await server.register(require('inert'));
  4.  
  5. server.route({
  6. method: 'GET',
  7. path: '/picture.jpg',
  8. handler: function (request, h) {
  9.  
  10. return h.file('/path/to/picture.jpg');
  11. }
  12. });
  13.  
  14. await server.start();
  15.  
  16. console.log('Server running at:', server.info.uri);
  17. };
  18.  
  19. start();

如上所示,这就是你返回 h.file(path) 的基本方式。

相对路径

为了简化操作,特别是如果有多个需要返回文件的路由,你可以在服务器中配置基本路径,之后只将相对路径传递给 h.file():

  1. 'use strict';
  2.  
  3. const Hapi = require('hapi');
  4. const Path = require('path');
  5.  
  6. const server = Hapi.server({
  7. routes: {
  8. files: {
  9. relativeTo: Path.join(__dirname, 'public')
  10. }
  11. }
  12. });
  13.  
  14. const start = async () => {
  15.  
  16. await server.register(require('inert'));
  17.  
  18. server.route({
  19. method: 'GET',
  20. path: '/picture.jpg',
  21. handler: function (request, h) {
  22.  
  23. return h.file('picture.jpg');
  24. }
  25. });
  26.  
  27. await server.start();
  28.  
  29. console.log('Server running at:', server.info.uri);
  30. };
  31.  
  32. start();

当在 server.options.routes 中设置一个选项时,如上所述,它将应用于 所有的 路由。你还可以修改这些选项,包括每个路由级别的 relativeTo 选项。

文件 handler

上述路由的替代方法是使用 file handler:

  1. server.route({
  2. method: 'GET',
  3. path: '/picture.jpg',
  4. handler: {
  5. file: 'picture.jpg'
  6. }
  7. });

文件 handler 选项

我们还可以将参数指定为接受 request 对象,并返回表示文件路径字符串的函数 (绝对路径或者相对路径):

  1. server.route({
  2. method: 'GET',
  3. path: '/{filename}',
  4. handler: {
  5. file: function (request) {
  6. return request.params.filename;
  7. }
  8. }
  9. });

它也可以是具有 path 属性的对象。当在 handler 中使用对象时,我们可以附加一些别的东西,如设 Content-Disposition 头并允许压缩文件。如下:

  1. server.route({
  2. method: 'GET',
  3. path: '/script.js',
  4. handler: {
  5. file: {
  6. path: 'script.js',
  7. filename: 'client.js', // 修改 Content-Disposition 头中的文件名
  8. mode: 'attachment', // 指定 Content-Disposition 是一个附件
  9. lookupCompressed: true // 如果请求允许,将允许查找 script.js.gz
  10. }
  11. }
  12. });

目录 handler

file handler 之外,inert 也有一个额外的 directory handler 允许一个路由提供多份文件。要使用它,必须使用参数指定路径。 参数的名称无关紧要,你也可以在参数上使用星号扩展名来限制文件的深度。目录 handler 的基本用法如下:

  1. server.route({
  2. method: 'GET',
  3. path: '/{param*}',
  4. handler: {
  5. directory: {
  6. path: 'public'
  7. }
  8. }
  9. });

目录 handler 选项

上述路由将通过在 public 目录中查找匹配的文件名来响应任何请求。这里需要注意的是,在此配置中对 / 的请求将会使用 HTTP 403 响应进行回复。我们可以通过添加索引文件的方式来解决这个问题。默认情况下,hapi 会在目录中搜索名为 index.html 的文件。我们可以通过将 index 选项设置为 false 来禁用提供索引文件,或者我们可以指定 inert 可以查找的索引文件数组:

  1. server.route({
  2. method: 'GET',
  3. path: '/{param*}',
  4. handler: {
  5. directory: {
  6. path: 'public',
  7. index: ['index.html', 'default.html']
  8. }
  9. }
  10. });

一个发往 / 的请求首先尝试去加载 /index.html, 之后再加载 /default.html。当没有可用的索引文件时, inert 可以以列表的形式显示这个目录下的内容。你可以通过设置 listing 属性为 true 来开启这个选项,如:

  1. server.route({
  2. method: 'GET',
  3. path: '/{param*}',
  4. handler: {
  5. directory: {
  6. path: 'public',
  7. listing: true
  8. }
  9. }
  10. });

现在,对 / 的请求将会回复一个显示目录内容的 HTML。使用启用了列表的目录 handler 时,默认情况下隐藏文件不会显示在列表中,可以通过将 showHidden 选项设置为 true 来显示。与文件 handler 一样,目录 handler 也有一个 lookupCompressed 的选项用于提供预压缩文件。你还可以设置一个 defaultExtension,如果找不到原始路径,它将附加到请求中。这意味着对 /bacon 的请求也会尝试文件 /bacon.html