AWS-SDK v3 - 使用 Typescript 下载文件
AWS-SDK v3 - Download file with Typescript
编写基于 Typescript 的 Lambda 以从 S3 存储桶下载文件进行处理,但 运行 AWS SDK v3 出现问题。
我收到错误 "属性 'pipe' 在类型 'Readable | ReadableStream | Blob' 上不存在。属性 'pipe' 不存在存在于“ReadableStream”类型上。
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
const s3Client = new S3Client();
const command = new GetObjectCommand({ Bucket: myBucket, Key: myFile });
const s3Item = await s3Client.send(command);
s3Item.Body.pipe(createWriteStream(fileName));
已尝试使用 .pipeTo 和 .pipeThrough,但它们实际上报告了相同的错误。
关于为什么这不起作用或如何通过 SDK v3 实现下载有任何想法吗?
我很难找到下载示例,即使官方 AWS 文档也涵盖了上传和其他步骤,但没有涵盖下载。 AWS S3 Examples
Body
的类型相当笨拙 Readable | ReadableStream | Blob | undefined
。这是因为库在节点和浏览器中都可用,但不幸的是只是将它们全部塞进一个定义中。
- 如果使用节点,它将是
Readable
- 在现代浏览器中,它将是
ReadableStream
- 在旧版浏览器中,它将是
Blob
我没发现Body
是undefined
的情况,不过翻了一下源码,好像是底层http层的神器。到目前为止,只要假设它已定义,我就没问题,这使得辅助方法的签名更加方便。但是,在某些情况下,假设我没有遇到过是不安全的。
因此,对于节点,你可以使用这样的东西:
import { Readable } from 'stream';
import { GetObjectCommandOutput } from '@aws-sdk/client-s3';
export const asStream = (response: GetObjectCommandOutput) => {
return response.Body as Readable;
};
export const asBuffer = async (response: GetObjectCommandOutput) => {
const stream = asStream(response);
const chunks: Buffer[] = [];
return new Promise<Buffer>((resolve, reject) => {
stream.on('data', (chunk) => chunks.push(chunk));
stream.on('error', (err) => reject(err));
stream.on('end', () => resolve(Buffer.concat(chunks)));
});
};
export const asString = async (response: GetObjectCommandOutput) => {
const buffer = await asBuffer(response);
return buffer.toString();
};
或者如果你想对undefined
更严格:
const getBody = (response: GetObjectCommandOutput) => {
return response.Body && (response.Body as Readable);
};
const getBodyAsBuffer = async (response: GetObjectCommandOutput) => {
const stream = getBody(response);
if (stream) {
const chunks: Buffer[] = [];
return new Promise<Buffer>((resolve, reject) => {
stream.on('data', (chunk) => chunks.push(chunk));
stream.on('error', (err) => reject(err));
stream.on('end', () => resolve(Buffer.concat(chunks)));
});
}
};
const getBodyAsString = async (response: GetObjectCommandOutput) => {
const buffer = await getBodyAsBuffer(response);
return buffer?.toString();
};
在浏览器中,以下内容适用于现代浏览器,但如果您的应用支持 IE,请务必注意此处的兼容性,因为它无法处理旧版浏览器 Blob
响应:https://developer.mozilla.org/en-US/docs/Web/API/Streams_API#browser_compatibility
import { GetObjectCommandOutput } from '@aws-sdk/client-s3';
export const asStream = (s3Response: GetObjectCommandOutput) => {
return s3Response.Body as ReadableStream;
};
export const asBlob = async (response: GetObjectCommandOutput) => {
return await new Response(asStream(response)).blob();
};
export const asString = async (response: GetObjectCommandOutput) => {
return await new Response(asStream(response)).text();
};
我认为在长期 运行 中,@aws-sdk/lib-storage
将需要一个与其 Upload
类似的 Download
,但还没有听说它有任何积压迄今。请参阅此 GitHub 问题以进行长期讨论:https://github.com/aws/aws-sdk-js-v3/issues/1877
显然,对于节点来说,s3Item.Body是可读的。在浏览器中,它是一个 ReadableStream 或 Blob(参见https://github.com/aws/aws-sdk-js-v3/issues/1877)。
import {
S3Client,
GetObjectCommand,
GetObjectCommandOutput
} from '@aws-sdk/client-s3';
import internal from 'stream';
const s3Client = new S3Client();
const command = new GetObjectCommand({
Bucket: myBucket,
Key: myFile
});
const s3Item = await s3Client.send(command);
const commandResult: GetObjectCommandOutput =
await s3Client.send(new GetObjectCommand(getObjectParams));
if (commandResult.Body instanceof internal.Readable) {
let readableStream: internal.Readable =
commandResult.Body as internal.Readable;
readableStream = readableStream.pipe(...);
} else {
console.log(`GetObjectCommand should return an
internal.Readable object. Maybe the code is
running in the Browser?`);
}
编写基于 Typescript 的 Lambda 以从 S3 存储桶下载文件进行处理,但 运行 AWS SDK v3 出现问题。
我收到错误 "属性 'pipe' 在类型 'Readable | ReadableStream | Blob' 上不存在。属性 'pipe' 不存在存在于“ReadableStream”类型上。
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
const s3Client = new S3Client();
const command = new GetObjectCommand({ Bucket: myBucket, Key: myFile });
const s3Item = await s3Client.send(command);
s3Item.Body.pipe(createWriteStream(fileName));
已尝试使用 .pipeTo 和 .pipeThrough,但它们实际上报告了相同的错误。
关于为什么这不起作用或如何通过 SDK v3 实现下载有任何想法吗?
我很难找到下载示例,即使官方 AWS 文档也涵盖了上传和其他步骤,但没有涵盖下载。 AWS S3 Examples
Body
的类型相当笨拙 Readable | ReadableStream | Blob | undefined
。这是因为库在节点和浏览器中都可用,但不幸的是只是将它们全部塞进一个定义中。
- 如果使用节点,它将是
Readable
- 在现代浏览器中,它将是
ReadableStream
- 在旧版浏览器中,它将是
Blob
我没发现Body
是undefined
的情况,不过翻了一下源码,好像是底层http层的神器。到目前为止,只要假设它已定义,我就没问题,这使得辅助方法的签名更加方便。但是,在某些情况下,假设我没有遇到过是不安全的。
因此,对于节点,你可以使用这样的东西:
import { Readable } from 'stream';
import { GetObjectCommandOutput } from '@aws-sdk/client-s3';
export const asStream = (response: GetObjectCommandOutput) => {
return response.Body as Readable;
};
export const asBuffer = async (response: GetObjectCommandOutput) => {
const stream = asStream(response);
const chunks: Buffer[] = [];
return new Promise<Buffer>((resolve, reject) => {
stream.on('data', (chunk) => chunks.push(chunk));
stream.on('error', (err) => reject(err));
stream.on('end', () => resolve(Buffer.concat(chunks)));
});
};
export const asString = async (response: GetObjectCommandOutput) => {
const buffer = await asBuffer(response);
return buffer.toString();
};
或者如果你想对undefined
更严格:
const getBody = (response: GetObjectCommandOutput) => {
return response.Body && (response.Body as Readable);
};
const getBodyAsBuffer = async (response: GetObjectCommandOutput) => {
const stream = getBody(response);
if (stream) {
const chunks: Buffer[] = [];
return new Promise<Buffer>((resolve, reject) => {
stream.on('data', (chunk) => chunks.push(chunk));
stream.on('error', (err) => reject(err));
stream.on('end', () => resolve(Buffer.concat(chunks)));
});
}
};
const getBodyAsString = async (response: GetObjectCommandOutput) => {
const buffer = await getBodyAsBuffer(response);
return buffer?.toString();
};
在浏览器中,以下内容适用于现代浏览器,但如果您的应用支持 IE,请务必注意此处的兼容性,因为它无法处理旧版浏览器 Blob
响应:https://developer.mozilla.org/en-US/docs/Web/API/Streams_API#browser_compatibility
import { GetObjectCommandOutput } from '@aws-sdk/client-s3';
export const asStream = (s3Response: GetObjectCommandOutput) => {
return s3Response.Body as ReadableStream;
};
export const asBlob = async (response: GetObjectCommandOutput) => {
return await new Response(asStream(response)).blob();
};
export const asString = async (response: GetObjectCommandOutput) => {
return await new Response(asStream(response)).text();
};
我认为在长期 运行 中,@aws-sdk/lib-storage
将需要一个与其 Upload
类似的 Download
,但还没有听说它有任何积压迄今。请参阅此 GitHub 问题以进行长期讨论:https://github.com/aws/aws-sdk-js-v3/issues/1877
显然,对于节点来说,s3Item.Body是可读的。在浏览器中,它是一个 ReadableStream 或 Blob(参见https://github.com/aws/aws-sdk-js-v3/issues/1877)。
import {
S3Client,
GetObjectCommand,
GetObjectCommandOutput
} from '@aws-sdk/client-s3';
import internal from 'stream';
const s3Client = new S3Client();
const command = new GetObjectCommand({
Bucket: myBucket,
Key: myFile
});
const s3Item = await s3Client.send(command);
const commandResult: GetObjectCommandOutput =
await s3Client.send(new GetObjectCommand(getObjectParams));
if (commandResult.Body instanceof internal.Readable) {
let readableStream: internal.Readable =
commandResult.Body as internal.Readable;
readableStream = readableStream.pipe(...);
} else {
console.log(`GetObjectCommand should return an
internal.Readable object. Maybe the code is
running in the Browser?`);
}