无中转上传
无中转上传允许你将传入的多部分流流式传输到 Amazon S3 或 Cloudinary 等云服务,而无需在你的服务器上处理它们。流程如下所示:
- 用户上传文件。
- 请求到达你的服务器。
- 你无需解析请求并从中读取数据,而是将流传输到外部云服务。
由于是直接通过管道传输流,因此你的 AdonisJS 应用程序不必分配任何额外的内存或 CPU 计算来解析和保存磁盘上的数据。
什么时候不使用无中转上传?#
就像你将在本指南后面部分看到的那样,直接文件上传很复杂,需要你直接处理流。
如果你的应用程序不处理大文件上传,我们建议使用 标准文件上传。请记住,有时编写更简单的代码甚至会获得一些性能提升。
用法#
第一步是禁用 config/bodyparser.ts
文件中自动处理。禁用自动处理后,bodyparser 中间件会将多部分流转发到你的控制器,以便您可以手动处理它。
你可以通过将 autoProcess
属性设置为 false
来禁用整个应用程序的自动处理。
multipart: {
autoProcess: false
}
你也可以通过将它们的路由匹配添加到 processManually
数组来对特定的路由禁用。
processManually: ['/drive']
处理多部分流#
你可以按如下方式处理控制器内部的多部分流:
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class DriveController {
public async store({ request }: HttpContextContract) {
request.multipart.onFile('input_field_name', {}, (part) => {
someSdk.uploadStream(part)
})
await request.multipart.process()
}
}
-request.multipart.process()
最先处理多部分流。
-request.multipart.onFile
方法允许你通过定义回调来处理给定文件输入的流。
- 回调方法接收流实例 (
part
) 作为第一个参数,可以将此流写入你想要的任何地方。
获取处理后的流文件#
一旦处理给定文件的流得到 (成功或有错误) 的结果,就可以使用 request.file
方法进行访问。例如:
request.multipart.onFile('input_field_name', {}, (part) => {
someSdk.uploadStream(part)
})
await request.multipart.process()
const file = request.input('input_field_name')
if (file.hasErrors) {
return file.errors
}
验证流#
你还可以在流被写入时,对流中的每个块 (chunk) 进行验证,这需要你将每个块作为第二个参数传递给 onFile
回调。
request.multipart.onFile(
'input_field_name',
{
extnames: ['pdf', 'jpg', 'png', 'doc', 'xls'],
size: '200mb',
},
(part, reportChunk) => {
part.pause()
part.on('data', reportChunk)
someSdk.uploadStream(part)
})
- 首先,你必须为
extname
和size
定义验证规则。 - 接下来,使用
reportChunk
方法并将每个块报告给内部辅助函数。
-reportChunk
方法将在流传输时监控流,如果任何验证规则未满足,则会发出错误。 - 一旦可读流上的
reportChunk
方法发出错误,可写流 (你的 SDK) 将 / 应该中止上传。
你注意到 part.pause
语句了吗?#
在定义 part.on('data')
事件侦听器之前,你必须 暂停流。否则,流将在你的 SDK 准备好使用它之前开始传输数据。
错误处理#
onFile
回调中发生的任何错误都会添加到文件实例中,你可以按如下方式访问它们。
request.multipart.onFile('input_field_name', {}, (part) => {
throw new Error('blow up the stream')
})
await request.multipart.process()
const file = request.input('input_field_name')
console.log(file.errors) // 将包含流产生的所有错误
将元数据附加到处理后的流#
你可以将元数据附加到已处理的流文件,这样将从 onFile
回调返回一个对象。例如,它可以是保存上传到云服务的文件的 URL 的对象。
request.multipart.onFile('input_field_name', {}, (part, reportChunk) => {
part.pause()
part.on('data', reportChunk)
const url = await someSdk.uploadStream(part)
return { url }
})
url
将在 file.meta
属性中可用。
await request.multipart.process()
const file = request.input('input_field_name')
console.log(file.meta) // { url: '...' }
注意事项#
直接使用流时,你无法在处理整个流之前访问表单输入字段。这是因为表单字段和文件都是单个流的一部分,因此它们仅在处理流时可用。
注意:流处理期间表单域可能不可用
request.multipart.onFile('input_field_name', {}, (part) => {
// 可用与否取决于字段在流中的位置
request.input('some_field')
})
await request.multipart.process()
注意:可以流处理完毕后访问表单域
request.multipart.onFile('input_field_name', {}, (part) => {
})
await request.multipart.process()
// 处理方法后进行访问
request.input('some_field')
它与 AWS 直接上传有何不同?#
AWS 允许直接从浏览器上传文件 , 甚至不需要先到达你的服务器。
AdonisJS 直接上传是 AWS 直接上传的替代方法,但这两种方法都有其优点和缺点,如下所示。
AWS 直接上传#
- 直接从浏览器处理。
- 需要额外的 HTTP 请求来生成身份验证签名。
- 使用客户端 file.type 属性来检测文件内容类型。这很容易被欺骗。
- 需要桶策略来验证文件类型和大小。
- 文件上传通常更快,并且不需要在你的服务器上进行计算。
AdonisJS 直接上传#
- 从服务器处理。
- 使用文件 magic number 来检测服务器上文件的内容类型。
- 使用标准的服务器端验证。
- 即使文件是直接流式传输的,你的服务器仍然必须接受请求。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。