node.js 中 `.on('finish')` 等流事件监听器本身不支持 `async/await` 返回值,需手动封装为 promise 才能等待异步操作完成并获取结果(如签名 url)。
在 Node.js 的流(Stream)处理中,.on() 方法注册的是事件回调函数,其返回值(包括 async 函数的 return)不会被传播到外部作用域——它仅作用于事件系统内部,与调用链无关。因此,你原代码中 return signedUrls[0] 实际上未被任何变量捕获,uploadedUrl 得到的只是流管道对象(writeStream),而非期望的签名 URL。
要真正“等待”上传完成并获取 getSignedUrl() 的结果,必须将整个流生命周期封装为一个 Promise,并在 'finish' 事件中调用 resolve(),在 'error' 事件中调用 reject():
// ✅ 正确做法:封装为 Promise 并 await
const uploadedUrl = await new Promise((resolve, reject) => {
response.data
.pipe(writeStream)
.on('finish', async () => {
try {
console.log('Successfully uploaded image');
const [signedUrl] = await file.getSignedUrl({
action: 'read',
expires: '03-09-2491' // 建议使用时间戳或 Date 对象,避免字符串解析歧义
});
console.log('signedUrl:', signedUrl);
resolve(signedUrl); // ✅ 向外传递结果
} catch (err) {
console.error('Failed to generate signed URL:', err);
reject(err);
}
})
.on('error', (err) => {
console.error('Error uploading image:', err);
reject(err);
});
});
console.log('uploadedUrl:', uploadedUrl); // ✅ 此时已为有效签名 URL 字符串⚠️ 注意事项:
务必用 await 或 .then() 处理,不可忽略;通过 Promise 封装,你就能真正实现「等待流结束 → 异步生成签名 URL → 返回最终结果」的线性控制流,彻底解决“返回值来得太晚”的表象问题——本质是事件回调与 Promise 链的范式差异。