推荐阅读
我们去 google awa upload from browser
, 总能看见一个包的身影 —— @aws-sdk/s3-request-presigner
, 以及一些关键字 —— getSignedUrl
or presign
, 我遇到了各种各样的干扰:
如果我们搜这个包 @aws-sdk/s3-request-presigner
, 会发现 google 第一条就是 This API Documentation is now deprecated, 经过测试, 要用的就是这个包, 估计那个 deprecated 只是说那个文档 deprecated...
还有一些干扰文档, 如:
// aws-sdk 已经过时了
const AWS = require('aws-sdk')
const s3 = new AWS.S3()
const url = s3.getSignedUrl(/* ... */)
aws-sdk
已经过时了, 我们应该用 @aws-sdk
系列包。
排除干扰, 然后照着 @aws-sdk/s3-request-presigner 文档抄就可以了
即使照着抄, 如果你使用的是 pnpm
, 仍然会报 warning
(虽然并不影响运行), 看 log 会发现它缺少一个包 @aws-sdk/signature-v4-crt
, install
就好了。
代码放这, 以供参考
// server side
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import {
S3Client,
PutObjectCommand,
ObjectCannedACL,
} from "@aws-sdk/client-s3";
import type { PutObjectCommandInput } from "@aws-sdk/client-s3";
const s3Client = new S3Client({
region: process.env.AWS_REGION,
// 所需其他参数请参考 S3Client 文档
});
type RequestUploadConfig = Pick<File, "type" | "size">;
export async function requestUpload(f: RequestUploadConfig) {
// 我们可以在这里做鉴权及其他一些限制逻辑
// ...
const uploadParams: PutObjectCommandInput = {
Bucket: process.env.AWS_BUCKET,
/**
* Key 实际上是上传的 pathname,
* 但有一点需要注意, 不包括前缀 '/',
* 即: 如果你的目标路径是 '/public/dir/file.txt',
* 那 Key 应该是: 'public/dir/file.txt';
*/
Key: uploadKey,
// 我们可以限制用户上传的 type & size, 其他更多限制可以看文档
ContentType: f.type,
ContentLength: f.size,
// 权限任选 public or private
ACL: ObjectCannedACL.public_read,
};
const command = new PutObjectCommand(uploadParams);
// 把预签名的 url 返回给客户端就好了
return getSignedUrl(s3Client, command, { expiresIn: 3600 });
}
// client side
const url = await requestUpload({
type: f.type,
size: f.size,
});
await fetch(url, {
// 注意是 PUT, 而非 POST 或其他
method: "PUT",
body: f,
}).then((res) => {
if (!res.ok) {
throw new Error(`上传失败: ${res.statusText}`);
}
});
// ok 上传成功
上面说了 Key 不能带前缀 '/', 因为当你调用 aws 删除命令时, 带 '/' 的话不能成功删除, aws 也不会抛错, 会静默地失败。
await new DeleteObjectCommand({
Bucket: process.env.AWS_BUCKET,
// 错误, 这样是删不掉的, 不能带 '/' 前缀
Key: "/public/dir/file.txt",
// 正确的 Key 应当是 'public/dir/file.txt'
});
如非特别声明,本站作品均为原创,遵循【自由转载-保持署名-非商用-非衍生 创意共享 3.0 许可证】。
对于转载作品,如需二次转载,请遵循原作许可。