首页
Preview

使用React.js和Node.js上传文件

上传文件是网页开发人员最常见的任务之一。使用PHP或其他服务器端框架时,这是一个相当简单的操作。然而,使用Node.js时并不那么简单,除非你了解如何使用Buffer API读取二进制文件流(即将文件内容作为二进制代码上传)。幸运的是,Node.js社区提供了几种解决方案。

项目设置

我们在客户端使用React.js,Express.js作为中间(协调)层和外部REST API,这不是React/Express体系结构的一部分。处理文件的一种方法是直接通过浏览器将它们上传到服务器,但这在每种情况下可能都不是理想的,例如,当API位于不同的域或者你想在发送到API之前修改文件时。这种情况下,Node服务器是一个完美的解决方案。然而,正如我之前提到的,开发人员必须在这里跳过一些障碍。接下来我们看看如何做到这一点。

客户端

这是一个带有事件处理程序的简单输入字段:

<input type="file" onChange={e => this.props.uploadFile(e.target.files[0], e.target.files[0].name)} />

让我们看看客户端发生了什么。当输入改变(文件被添加)时,事件处理程序将触发Redux action creator并将文件和名称作为参数传递。操作创建者将构建FormData对象,这是处理multipart/form-data所必需的。在我们将文件和名称附加到表单的数据对象之后,它就可以传递到服务器了。Axios是一个很好的HTTP请求库。在这种情况下,我们将数据POST到Node.js路由。让我们看看服务器上发生了什么。

服务器

一旦客户端提供了文件和与文件相关的其他元信息,服务器就必须知道如何处理二进制文件。几个库可以帮助解决这个问题。我们将使用Express.js团队维护的Multer

让我们看看服务器上发生了什么。首先,我们配置Multer使用本地/files/目录存储来自客户端上传的文件。在我们将其发送到REST API之前,将文件保存在某个地方非常重要,因为在大多数情况下,我们将不得不提供完整的文件路径。另一个选择是将其保存在内存中,但这可能会导致服务器崩溃。接下来,我们要确保生成具有文件扩展名的唯一文件名(默认情况下不提供)。

下一步是创建实际的路由,客户端发送FormData,并且我们传递Multer中间件。当路由接收到文件时,它首先通过中间件并使用新生成的文件名存储在我们的/files目录中。所以,当我们到达回调(可以重构为自定义中间件)时,文件可用作req对象的一部分。从这里开始,我们可以做任何需要做的事情,在这种情况下,调用我们的外部API(可以是S3或任何处理文件的API)并传递文件和元信息。

2017年6月25日更新。使用流直接上传到cloudinary CDN。

上传文件的另一种方法是使用Node.js流而不是在将其发送到CDN之前存储临时文件。下面是中间件的样子。

const cloudinary = require('cloudinary');
const multer = require('multer');
const stream = require('stream');

const storage = multer.memoryStorage();
const upload = multer({ storage: storage });

cloudinary.config({
  cloud_name: 'your_cloud_name',
  api_key: 'your_api_key',
  api_secret: 'your_api_secret'
});

module.exports = app => {
  app.post('/upload', upload.single('file'), (req, res) => {
    const stream = cloudinary.uploader.upload_stream(result => {
      console.log(result);
      res.send(result);
    });
    streamifier.createReadStream(req.file.buffer).pipe(stream);
  });
};

使用更新的cloudinary API创建中间件

一旦有了这个处理流将文件流式传输到CDN的中间件,就可以添加新路由来触发它。

现在你可以从React(或任何其他客户端框架)上传文件了。这是一个例子:

axios.post('/upload', formData, {
  headers: { 'Content-Type': 'multipart/form-data' }
})
.then(response => console.log(response))
.catch(err => console.log(err));

结论

这可能看起来像一个对一个常见问题的过度工程化的解决方案。然而,在将文件发送到另一个来源之前,将需要使用节点服务器的情况。当文件上传不是表单提交方法的一部分,并且需要独立处理文件上传时,这将特别棘手。

版权声明:本文内容由TeHub注册用户自发贡献,版权归原作者所有,TeHub社区不拥有其著作权,亦不承担相应法律责任。 如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

点赞(0)
收藏(0)
一个人玩
先找到想要的,然后出发

评论(0)

添加评论