首页 > 解决方案 > res.sendFile(file) 和 express.static(file) 之间的异常差异

问题描述

我正在制作一个网络应用程序,我可以在其中上传一些我制作的 Three.js 虚拟现实项目并将它们提供给浏览器。

当我开始制作它时,我对我的 VR 文件夹进行了快速测试,看看是否可行。代码有效,因此我开始花费大量时间开发应用程序。我使用的代码如下:

app.use('/', express.static('/Users/virtuload-beta/backend/uploads/065fe1658b1374605f31d100eb1e7a1a1568654427336/Nancy_Collins_118226967_v2/'))

这工作得很好,浏览器渲染了我的 VR 场景。我还想确保文件可以动态提供(例如,用户单击要渲染的 VR 场景并使用指向 url 的 href 进行渲染),因此我执行了以下代码,它也可以正常工作:

const filepath = '065fe1658b1374605f31d100eb1e7a1a1568654427336/Nancy_Collins_118226967_v2/'
app.use('/', express.static(`/Users/virtuload-beta/backend/uploads/${filepath}`))

我现在基本上完成了应用程序,除了我有一个大问题,当我使用指定的 index.html 文件(您需要使用 res.sendFile)提供 VR 文件夹时,浏览器无法读取文件夹中的文件,我只是得到红色错误。

我的函数不再作为静态文件了,它从url中获取id,从mongodb中找到文件路径,如下:

const servepath = (req, res, next) => {
    let id = req.params.id
    Upload.findById(id)
      .populate('Upload')
      .select('relPath') //relPath = /folder/subfolder
      .exec(function (err, upload) {
        if (err) {
          res.send(err)
          console.log(err)
        } else {
          const dir = path.join(__dirname, '..', '../vr/uploads')
          const filepath = `${upload.relPath}`
          const fulldir = path.join(dir, filepath)
          console.log(fulldir)
              try {
                    res.sendFile('index.html', {root: `${fulldir}`});

                }
              }
              catch (e) {
                console.error(e)
              }
          // return next();
        }
      })
}

浏览器正在查找 html 文件,但无法用它解析 JS 文件:

GET http://localhost:3000/api/5d8b74be2af25086ab77fef7/js/three.js net::ERR_ABORTED 404(未找到)vr:21 GET http://localhost:3000/api/5d8b74be2af25086ab77fef7/js/OrbitControls.js网络: :ERR_ABORTED 404 (未找到) vr:22 GET http://localhost:3000/api/5d8b74be2af25086ab77fef7/js/GLTFLoader.js net::ERR_ABORTED 404 (未找到) vr:23 GET http://localhost:3000/api /5d8b74be2af25086ab77fef7/js/FBXLoader.js net::ERR_ABORTED 404(未找到)vr:24 GET http://localhost:3000/api/5d8b74be2af25086ab77fef7/js/inflate.min.js net::ERR_ABORTED 404(未找到)vr :25 GET http://localhost:3000/api/5d8b74be2af25086ab77fef7/js/WebGL.js net::ERR_ABORTED 404 (Not Found) vr:118 GEThttp://localhost:3000/api/5d8b74be2af25086ab77fef7/MainScene.js net::ERR_ABORTED 404(未找到)

当我将文件路径硬编码到我在此处指定的第一行代码(express.static)中时,vr 呈现完美...我尝试将文件作为静态文件提供,但您不能动态执行此操作,因此名称“静态”文件..有人知道为什么会这样吗?

我对标题了解不多,可能是我对标题缺乏了解吗?

标签: node.jsexpressstatic

解决方案


您的servepath处理程序显然处理对GET /api/:id. 当浏览器接收到index.html匹配id参数的内容时,它可能会找到表示为相对路径的引用,例如<script src="js/three.js">. 要构建此资源的完全限定地址,它使用当前文件的位置。在你展示的情况下,这index.html似乎是http://localhost:3000/api/5d8b74be2af25086ab77fef7

解决此问题的(相当)快速方法是:

  • 静态公开您的项目(express.static在公用文件夹中显示所有上传内容,显然/vr/uploads现在结束)
  • 然后,不是index.html直接提供 from ,而是/api/:id将此路由用作到正确静态位置的重定向

像这样的东西:

// expose all uploads, under the URL http://localhost:3000/uploaded-projects/*
app.use(
  '/uploaded-projects',
  express.static(path.join(__dirname, '../../vr/uploads'))
);
// handler to match a Mongo project ID with a public path under /uploaded-projects
app.get(`/api/:id`, (req, res) => {
  Upload.findById(req.params.id)
  .populate('Upload')
  .select('relPath')
  .exec((err, data) => {
    // ko: explicitly use an HTTP status otherwise it's 200
    if (err) return res.status(500).send(err);
    // ok: tell browser 302 + proper Location header
    res.redirect(`/uploaded-projects/${data.relPath}/index.html`);
  });
});

可能需要更多的努力,您可以更改您的前端,而不是使用项目列表中的 ID,而是使用relPath(您可以将其提供给前端,因为您已经提供了 ID,并且它relPath在里面Mongo 文档)和静态树的硬编码路径(在我的草图中/uploaded-projects)。这将允许前端直接构建正确的 URL,从而避免联系服务器获取 302,您可以摆脱这/api/:id条路线。


推荐阅读