You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 11:02:08