You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Hapijs v17中如何借助Inert实现文件强制下载?

在Hapi.js v17中使用Inert实现文件强制下载

你的思路完全正确——强制文件下载的核心就是给响应设置Content-Disposition头为attachment,不过我们可以优化代码的写法、安全性和健壮性,让它更实用。

先看优化后的完整代码:

const path = require('path');
const mime = require('mime-types'); // 可选,用于动态匹配不同文件的MIME类型

server.route({
    method: 'GET',
    path: '/uploads/{file*}',
    handler: (req, h) => {
        // 构建绝对路径,避免因运行目录变化导致的文件找不到问题
        const uploadsRootDir = path.resolve(__dirname, './uploads');
        const targetFilePath = path.resolve(uploadsRootDir, req.params.file);
        
        // 安全防护:防止用户通过../等参数遍历服务器敏感目录
        if (!targetFilePath.startsWith(uploadsRootDir)) {
            return h.response('Invalid file request').code(403);
        }
        
        // 处理文件名编码,解决中文、空格或特殊字符导致的浏览器解析乱码问题
        const encodedFileName = encodeURIComponent(req.params.file);
        // 动态获取文件的MIME类型(如果只需要PDF,可直接写死为application/pdf)
        const fileContentType = mime.lookup(targetFilePath) || 'application/octet-stream';
        
        return h.file(targetFilePath, {
            contentType: fileContentType,
            headers: {
                'Content-Disposition': `attachment; filename="${encodedFileName}"`
            }
        });
    },
    options: {
        auth: false
    }
});

关键细节解释:

  • 绝对路径构建:用path.resolve代替相对路径,确保服务器无论在哪个目录启动,都能精准找到上传文件的位置。
  • 路径安全校验:添加了目录边界检查,避免恶意用户通过路径遍历攻击访问服务器上的敏感文件。
  • 文件名编码:通过encodeURIComponent处理文件名,解决包含特殊字符、中文时浏览器保存文件出现乱码的问题。
  • 灵活的MIME类型:借助mime-types包动态匹配文件类型,比硬编码application/pdf更适配多类型文件的下载场景;如果你的场景只需要PDF,直接保留固定值即可。
  • 简洁的配置方式:直接在h.file的options参数里配置响应头和内容类型,这是Hapi官方推荐的写法,比链式调用.header()更清晰易维护。

如果想保留你最初的链式写法,也是可行的,但要补上文件名编码的处理:

server.route({
    method: 'GET',
    path: '/uploads/{file*}',
    handler: (req, h) => {
        const encodedFileName = encodeURIComponent(req.params.file);
        return h.file(`./uploads/${req.params.file}`)
            .header('Content-Type', 'application/pdf')
            .header('Content-Disposition', `attachment; filename="${encodedFileName}"`);
    },
    options: {
        auth: false
    }
});

不过这种写法缺少路径安全校验,也存在相对路径的潜在问题,更推荐第一种优化后的方案。

内容的提问来源于stack exchange,提问作者Ali Hesari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:21:03