【问题标题】:Serve static files with ExpressJS Typescript NodeJS使用 ExpressJS Typescript NodeJS 提供静态文件
【发布时间】:2021-07-05 17:30:43
【问题描述】:

我正在尝试提供使用 ExpressJS 和 NodeJS 和 Typescript 上传的静态文件,但出现 404 错误。

我要读取的文件是 ./src/data/uploads/test.txt,我正在尝试直接从网络浏览器访问它。

注意:当我在 Javascript 中执行此操作时,它有效,但在 Typscript 中无效。

index.ts 文件(应用入口点)

import express from 'express';
import bodyParser from 'body-parser';
import helmet from 'helmet';
import {cdg, config} from './utils';
import {Mongoose} from './db/monogdb';
import { setRoutes } from './routes/route.decorators';
import cors from 'cors';
import './routes';

const app = express();

app.use(helmet());
app.use(cors());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use('/ftp', express.static('data/uploads'));

setRoutes(app);

app.listen(config.server.port, () => {
    cdg.konsole("Server connected! :: " + config.server.port + "!");
});

有没有使用 Typescript 提供静态文件的特定方法?

【问题讨论】:

  • 与所有此类问题一样,我们需要查看三件事以确切了解问题所在:1)您要静态提供的特定文件的示例以及它在本地的确切位置服务器端文件系统以及启动应用程序时它与当前工作目录的关系。 2) 您在 HTML 页面中用于引用该资源的确切 HTML 标记。 3) 您在浏览器控制台中得到的准确错误(显示浏览器请求的完整 URL)。有了这个,我们可以准确地展示如何修复您的静态服务。请将此信息添加到您的问题中。
  • 404 错误可能仅仅意味着您尝试读取的文件不存在。我试过你的代码,将端口设置为 3000,在 data/uploads/test.txt 创建一个文件,查询 localhost:3000/ftp/test.txt 并且它工作。

标签: node.js typescript express


【解决方案1】:

express.static() 的工作原理如下。您显然缺少其中一个步骤,但您的问题缺少详细信息,无法准确确定哪个步骤不正确。

首先,您定义一个包含一些参数的express.static() 中间件。在您的情况下,您已经定义了这个:

app.use('/ftp', express.static('data/uploads'));

有四个因素决定了它的工作方式:

  1. /ftp 必须位于此中间件匹配的任何 URL 的开头。
  2. 传入的 URL 请求以及它是如何由浏览器根据您在 HTML 中指定的方式形成的。
  3. 当前工作目录与data/uploads 组合以进行完整路径引用,或者您可以构建自己的绝对路径而不依赖于 cwd。
  4. express.static() 将尝试与传入 URL 的路径匹配的 cwd + /data/uploads 中的文件。

让我们进一步研究一下:

您的中间件将首先只查看以 /ftp 开头的 URL。然后,对于它看到的任何以 /ftp 开头的 URL,它应该获取 URL 的其余部分并将其附加到 data/uploads 并查看它在本地文件系统中找到匹配的文件。它将在请求时使用服务器进程中的当前工作目录来尝试解析相对路径data/uploads。当前工作目录(如果您没有以编程方式更改它)将取决于您的应用是如何启动的。

因此,如果您使用node index.js 启动您的应用程序,那么当前工作目录将是index.js 所在的目录,express static 将在下面的data/uploads 子目录中查找'index.js ` 是。

然后,我们需要看看指定这个静态资源的HTML标签是如何指定的。

例如,假设这是一个<img> 标签。如果您指定如下内容:

 <img src="/ftp/hello.jpg">

然后,浏览器将向您的服务器创建一个请求/ftp/hello.jpg。由于它确实以 /ftp 开头,因此您的 express.static() 中间件将采用路径的其余部分 /hello.jpg 并将其附加到 data/uploads 并构建如下所示的路径:

path.join(process.cwd(), 'data/uploads', '/hello.jpg')

而且,它会在您的本地文件系统中查找生成的文件。如果它找到该文件,那么它将提供该文件并将其作为响应返回。如果它没有找到那个确切的文件,那么它将调用next() 并继续路由到您的其他路由处理程序。

有一些常见的错误(可能出错的事情):

  1. 您没有在您的网页中指定与您的 express.static() 中间件行一致的正确 URL(包括您的中间件指定的 /ftp 前缀)。

  2. 您的中间件没有完全指向文件系统中的正确目录,因此它永远找不到任何东西。

  3. 您在网页中使用了相对 URL,浏览器将这些 URL 与您的网页路径相结合,导致它请求的内容与您想要的不同。网页中的静态资源 URL 应该几乎总是以 / 开头,因此它们不依赖于父页面的路径。

  4. 文件没有完全正确地位于您使用中间件指向的文件层次结构中(通常偏离一级)。


我还要提到另一件事。由于您使用的是 TypeScript,这意味着您必须先将脚本编译/构建为常规的 .js 脚本,然后才能运行它。这通常位于不同的目录位置。

这个不同的目录位置为您创造了不引用静态资源所在的正确目录的机会,因为它们可能相对于您的 TypeScript 文件,而不是您正在运行的构建的 Javascript 文件(这取决于您的构建脚本)。

同样,如果您向我们展示文件系统中的所有内容(TypeScript 文件、构建的 JS 文件、静态资源)以及引用静态资源的 HTML 标记的外观,我们可以帮助您更具体地进行调试。

【讨论】:

  • 我想提供来自 ./src/data/uploads/ 的文件,但编译后的版本位于 ../build。也许服务的位置应该是../build/data/uploads/,对吧?
  • @Couranos - 您必须从它们所在的任何位置提供文件,并且必须将 express.static() 指向它们所在的目录。因此,您可以将文件复制到构建脚本中指向的位置,也可以更改express.static() 正在寻找它们的位置。选择一个。
猜你喜欢
  • 2014-11-20
  • 2017-11-24
  • 2011-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多