使用Azure Function上传文件时返回“No file was uploaded.”错误求助
Azure Function 上传文件至Blob存储时request.file为undefined的问题排查
我正在尝试创建一个可将文件上传至Azure Storage Blob的Azure Function,使用Postman发送请求:将请求体设为form-data,键为file并附加测试图片,但响应始终返回“No file was uploaded.”。查看Azure日志流发现request.file为undefined,日志内容如下:
2024-01-22T17:21:14Z [Information] Request body: ReadableStream { locked: false, state: 'readable', supportsBYOB: false } 2024-01-22T17:21:14Z [Information] Request file: undefined 2024-01-22T17:21:14Z [Information] File uploaded: No file was uploaded
我的Azure Function代码如下:
const { BlobServiceClient } = require('@azure/storage-blob'); const { app } = require('@azure/functions'); const multer = require('multer'); const upload = multer(); // Azure Storage connection string const AZURE_STORAGE_CONNECTION_STRING = process.env['AZURE_STORAGE_CONNECTION_STRING']; app.http('postToICTDatabaseFiles', { methods: ['POST'], authLevel: 'anonymous', handler: async (request, context) => { try { // Log the request body for debugging context.log("Request body:", request.body); // Wrap the upload in a new Promise and await it const file = await new Promise((resolve, reject) => { upload.single('file')(request, {}, function (err) { if (err) { reject(err); } else { resolve(request.file); } }); }); // Log the file object for debugging context.log("Request file:", file); // Print to context.log the file name or if no file was uploaded context.log(`File uploaded: ${file ? file.originalname : 'No file was uploaded.'}`); // If file is undefined, return an error if (!file) { return { status: 400, body: 'No file was uploaded.' }; } // Create a BlobServiceClient object which will be used to create a container client const blobServiceClient = BlobServiceClient.fromConnectionString(AZURE_STORAGE_CONNECTION_STRING); // Get a reference to a container const containerClient = blobServiceClient.getContainerClient('files'); // Azure blob storage name // Create a new block blob and upload the file const blockBlobClient = containerClient.getBlockBlobClient(file.originalname); const uploadBlobResponse = await blockBlobClient.upload(file.buffer, file.buffer.length); context.log(`Upload block blob ${file.originalname} successfully`, uploadBlobResponse.requestId); // Respond with the result return { status: 200, body: `File uploaded successfully. Blob URL: ${blockBlobClient.url}` }; } catch (error) { // Handle errors // Log or console the error details for debugging context.log(error.message); return { status: 500, body: error.message }; } } });
问题核心原因
Azure Functions的HTTP请求对象并非Express框架的Request对象,multer依赖Express的req结构解析文件,直接传入Azure原生request对象会导致multer无法正确识别并解析multipart/form-data格式的请求体,日志中显示的ReadableStream就是原始未解析的请求体状态。
解决方法
方法1:使用Busboy手动解析(推荐)
Busboy是轻量级的multipart/form-data解析库,无需依赖Express生态,适配Azure Functions的请求流:
const { BlobServiceClient } = require('@azure/storage-blob'); const { app } = require('@azure/functions'); const Busboy = require('busboy'); const AZURE_STORAGE_CONNECTION_STRING = process.env['AZURE_STORAGE_CONNECTION_STRING']; app.http('postToICTDatabaseFiles', { methods: ['POST'], authLevel: 'anonymous', handler: async (request, context) => { try { return new Promise((resolve, reject) => { const busboy = new Busboy({ headers: request.headers }); let uploadedFile = null; // 监听文件字段 busboy.on('file', (fieldname, file, filename) => { if (fieldname === 'file') { const chunks = []; file.on('data', chunk => chunks.push(chunk)); file.on('end', () => { uploadedFile = { originalname: filename, buffer: Buffer.concat(chunks) }; }); } }); // 解析完成后处理上传 busboy.on('finish', async () => { if (!uploadedFile) { resolve({ status: 400, body: 'No file was uploaded.' }); return; } const blobServiceClient = BlobServiceClient.fromConnectionString(AZURE_STORAGE_CONNECTION_STRING); const containerClient = blobServiceClient.getContainerClient('files'); const blockBlobClient = containerClient.getBlockBlobClient(uploadedFile.originalname); const uploadResponse = await blockBlobClient.upload(uploadedFile.buffer, uploadedFile.buffer.length); context.log(`Uploaded ${uploadedFile.originalname} successfully`, uploadResponse.requestId); resolve({ status: 200, body: `File uploaded successfully. Blob URL: ${blockBlobClient.url}` }); }); // 处理解析错误 busboy.on('error', err => { context.log('Parsing error:', err.message); reject({ status: 500, body: err.message }); }); // 将Azure的请求流传入Busboy request.body.pipe(busboy); }); } catch (error) { context.log('Upload error:', error.message); return { status: 500, body: error.message }; } } });
方法2:适配Express请求对象(不推荐)
如果一定要用multer,需要将Azure的request对象转换为Express兼容格式,但存在兼容性风险:
// 在handler函数内添加转换逻辑 const rawBody = await request.text(); const expressReq = { headers: request.headers, body: rawBody, // 模拟Express req的必要属性 }; const file = await new Promise((resolve, reject) => { upload.single('file')(expressReq, {}, err => { if (err) reject(err); else resolve(expressReq.file); }); });
额外检查项
- 确认Postman请求的Content-Type自动设为
multipart/form-data(不要手动修改),且文件字段名严格为file - 验证Azure Function的环境变量
AZURE_STORAGE_CONNECTION_STRING配置正确 - 确保Blob存储容器
files已创建,且Function拥有该容器的写入权限
内容的提问来源于stack exchange,提问作者zucc0nit
相关产品推荐
相关产品推荐

