如何在Puppeteer Azure函数中使用Azure存储Blob上传文件
Azure Functions + Puppeteer 上传Blob存储PDF解决方案
首先纠正一个认知:Azure Functions 运行环境并非全文件系统只读,仅代码部署目录(/home/site/wwwroot)为只读,系统预留的临时目录为可写状态,完全可以满足临时存储待上传PDF的需求,这也是兼容性最高、最稳定的实现方案。
方案一:使用临时目录中转文件(推荐)
该方案完全兼容现有Puppeteer文件上传逻辑,无需修改页面交互代码,稳定性最高。
- 临时目录获取:直接调用Node.js内置
os.tmpdir()即可获取当前实例的可写临时路径,Linux环境下对应/tmp目录,目录为当前函数实例独占隔离,实例回收时会自动清理所有临时文件。 - 实现步骤:
- 放弃原有写入代码目录的
downloadToFile逻辑,改用Azure Blob SDK提供的downloadToBuffer()方法,直接将目标PDF文件读取为内存Buffer - 将Buffer写入临时目录下的随机命名文件,避免多请求并发时文件名冲突
- 将临时文件路径传入
fileChooser.accept()完成上传 - 上传流程结束后主动删除临时文件,避免占用实例临时存储空间
- 放弃原有写入代码目录的
参考实现代码:
const os = require('os'); const path = require('path'); const fs = require('fs/promises'); const { BlobServiceClient } = require('@azure/storage-blob'); // 初始化Blob客户端,使用存储账号连接字符串鉴权 const blobServiceClient = BlobServiceClient.fromConnectionString(process.env.BlobConnectionString); const containerClient = blobServiceClient.getContainerClient('你的PDF存储容器名'); // 原有文件选择器触发逻辑不变 const [fileChooser] = await Promise.all([ page.waitForFileChooser(), page.click('#upload-file-button'), ]); // 下载目标Blob为内存Buffer const blobClient = containerClient.getBlobClient(userInput.filename); const pdfBuffer = await blobClient.downloadToBuffer(); // 生成临时文件路径,加时间戳避免重名 const tempPdfPath = path.join(os.tmpdir(), `upload_${Date.now()}_${path.basename(userInput.filename)}`); await fs.writeFile(tempPdfPath, pdfBuffer); try { // 传入临时路径完成上传 await fileChooser.accept([tempPdfPath]); // 等待页面上传完成的状态标识,按需调整选择器和超时时间 await page.waitForSelector('.upload-success', { timeout: 30000 }); } finally { // 无论上传成功/失败都主动清理临时文件,删除失败无需额外处理,系统会自动回收 await fs.unlink(tempPdfPath).catch(() => {}); }
方案二:内存直传(不推荐)
Puppeteer原生fileChooser.accept方法仅支持传入本地文件路径,无法直接传入内存中的Blob/Buffer对象。如果要实现不落地直传,需要在页面上下文中覆写文件选择input的change事件,手动构造File对象注入,这种方式存在以下问题:
- 容易被页面的前端文件校验、分片上传逻辑拦截,兼容性差
- 需要额外处理页面的上传事件触发逻辑,维护成本高
仅当临时目录存在特殊使用限制时才考虑该方案,常规场景优先用临时目录中转方案。
内容的提问来源于stack exchange,提问作者floating-rhythm
相关产品推荐
相关产品推荐

