如何自动重命名Google云存储签名下载链接的文件?
问题:Google云存储签名下载链接自动重命名方案
我通过外部API获取Google云存储的签名直接下载链接,点击可自动下载文件,但文件名是默认值(如123456123456.csv.gz)。用Puppeteer打开链接下载无法自动重命名,修改URL里的文件名会触发SignatureDoesNotMatch错误,用axios/fs直接下载也没成功,求自动重命名的可行方案。
链接格式示例
https://storage.googleapis.com/(custom storage name)/(data extract id)/123456123456.csv.gz?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=(google service account credentials)&X-Goog-Date=(date)&X-Goog-Expires=(time until expiration)&X-Goog-SignedHeaders=host&X-Goog-Signature=(long string of number and letters)
当前Puppeteer代码
async function downloadFile (url) { try { const browser = await puppeteer.launch( {headless: false} ); const page = await browser.newPage(); await page.goto(`${url}`); await page.waitForTimeout(3000); // 防止下载延迟 await browser.close(); } catch (error) { console.error(error); } }
修改URL的尝试代码
... const autoFileName = '000000000000.csv.gz'; const customFileName = `${date}-${reportingLevel}.csv.gz`; for (let i = 0; i < urls.length; i++) { const newUrl = url.replace(autoFileName, customFileName); downloadFile(newUrl); ...
报错信息
This XML file does not appear to have any style information associated with it. The document tree is shown below. <Error> <Code>SignatureDoesNotMatch</Code> <Message>Access denied.</Message> <Details>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Details> <StringToSign>(sensitive information)</StringToSign> <CanonicalRequest>GET (sensitive information) UNSIGNED-PAYLOAD</CanonicalRequest> </Error>
可行解决方案
方案1:通过Puppeteer拦截下载并指定文件名
Google云存储的签名链接包含完整路径的签名,不能直接修改URL中的文件名,但可以通过Puppeteer的下载拦截功能,直接指定保存的文件名。
代码示例:
async function downloadFile(url, customFileName) { try { const browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); // 配置下载行为,指定保存目录和文件名 await page.setDownloadBehavior({ path: './downloads/', // 需提前创建该目录 filename: customFileName }); await page.goto(url); // 监听下载完成事件,替代固定等待时间 page.on('download', async (download) => { await download.saveAs(`./downloads/${customFileName}`); await browser.close(); }); } catch (error) { console.error(error); } } // 调用示例 const date = new Date().toISOString().split('T')[0]; const reportingLevel = 'summary'; const customFileName = `${date}-${reportingLevel}.csv.gz`; downloadFile(yourSignedUrl, customFileName);
方案2:用axios流式下载后重命名
之前用axios/fs失败大概率是没处理流式响应,签名链接支持直接流式下载,下载完成后再重命名即可。
代码示例:
const axios = require('axios'); const fs = require('fs'); const path = require('path'); async function downloadAndRename(url, customFileName) { try { const response = await axios({ url: url, method: 'GET', responseType: 'stream' // 启用流式下载,避免大文件占用内存 }); const tempPath = path.join('./downloads/', 'temp_download.tmp'); const writer = fs.createWriteStream(tempPath); response.data.pipe(writer); // 等待下载完成 await new Promise((resolve, reject) => { writer.on('finish', resolve); writer.on('error', reject); }); // 重命名为目标文件名 const finalPath = path.join('./downloads/', customFileName); fs.renameSync(tempPath, finalPath); console.log(`文件已保存:${finalPath}`); } catch (error) { console.error('下载失败:', error); } } // 调用示例 downloadAndRename(yourSignedUrl, `${date}-${reportingLevel}.csv.gz`);
方案3:通过Google云存储SDK下载(需权限)
如果拥有对应GCS服务账号权限,可以直接通过官方SDK获取文件并重命名,适合长期集成场景。
代码示例:
const { Storage } = require('@google-cloud/storage'); const fs = require('fs'); async function downloadFromGcs(bucketName, filePath, customFileName) { const storage = new Storage({ credentials: require('./service-account-key.json') // 你的服务账号密钥文件 }); const bucket = storage.bucket(bucketName); const file = bucket.file(filePath); await file.download({ destination: `./downloads/${customFileName}` }); console.log(`文件已保存:./downloads/${customFileName}`); } // 从签名链接中提取bucket和文件路径 const urlPath = yourSignedUrl.split('?')[0].split('/'); const bucketName = urlPath[3]; const filePath = urlPath.slice(4).join('/'); downloadFromGcs(bucketName, filePath, `${date}-${reportingLevel}.csv.gz`);
内容的提问来源于stack exchange,提问作者courtneymickelsen
相关产品推荐
相关产品推荐

