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

Next.js上传图片至Azure Blob容器后显示异常问题求助

解决Next.js上传图片到Azure Blob后无法正常显示的问题

我正在尝试从Next.js应用向Azure Blob存储POST图片,已创建Azure账户和容器,能完成上传但存在以下问题:

  • 未设置content-type时,Azure中显示二进制数据;
  • 设置content-type为image/jpeg后,显示损坏的图片图标;
  • 点击Azure生成的Blob URL时,控制台返回400错误:Failed to load resource: the server responded with a status of 400 (One of the request inputs is out of range.)

容器和Blob的访问级别已设为“Container”,理论上应该能正常查看图片。


原客户端上传代码

const ImageUploadForm = () => {
const [image, setImage] = useState<any>();

const handleSubmit = async (e) => {
const reader = new FileReader();
reader.readAsDataURL(e.target.files[0]);

    reader.onload = () => {
      setImage(reader.result);
    };
    reader.onerror = () => {
      console.log('reader.error', reader.error);
    };
};

const uploadImage = async () => {
try {
const headers = {
'Content-Type': 'image/jpeg',
};
const response = await fetch('/api/postImage', {
method: 'POST',
body: image,
headers: headers,
});
        if (response.ok) {
          console.log('Image uploaded successfully!');
        } else {
          console.error('Image upload failed.');
        }
      } catch (error) {
        console.error('Error uploading image:', error);
      }
};

return (
<>
<input type="file" accept="image/*" onChange={handleSubmit} />
<button onClick={uploadImage}>Ladda upp bild</button>
</>
);
};

原postImage API路由代码

import azureStorage from '../../app/lib/azureConnection';

export async function postImage(req: NextApiRequest, res: NextApiResponse) {
try {
const fileBuffer = Buffer.from(req.body, 'base64');
const fileName = 'example-14';
const imageUrl = await azureStorage.uploadImageToAzureStorage(fileBuffer, fileName, req.headers['content-type']);

    res.status(200).json(imageUrl);

} catch (error) {
console.log('error', error);
}
}

原azureStorage函数代码

import { BlobServiceClient } from '@azure/storage-blob';

const connectionString = process.env.AZURE_CONNECTION;
const blobServiceClient = BlobServiceClient.fromConnectionString(connectionString as string);
const containerName = 'wilmascontainer';

async function uploadImageToAzureStorage(fileBuffer, fileName, headers) {
const containerClient = blobServiceClient.getContainerClient(containerName);
const blockBlobClient = containerClient.getBlockBlobClient(fileName);
const blobHTTPHeaders = { blobContentType: headers };

await blockBlobClient.uploadData(
fileBuffer, {
blobHTTPHeaders,
},
);

return blockBlobClient.url;
}

问题根源

核心问题在于客户端上传的是带data:image/jpeg;base64,前缀的Data URL字符串,而非纯图片二进制数据,导致后端直接用Buffer.from(req.body, 'base64')解码时生成错误的文件内容,最终上传到Azure的是无效的图片数据。同时客户端设置的Content-Type与实际传输的数据格式不匹配,进一步引发解析问题。

具体修改步骤

1. 客户端代码修改

直接上传文件二进制数据,无需转换为Data URL,既高效又避免前缀问题:

const ImageUploadForm = () => {
  const [file, setFile] = useState(null);

  const handleFileChange = (e) => {
    setFile(e.target.files[0]);
  };

  const uploadImage = async () => {
    if (!file) return;
    
    try {
      const formData = new FormData();
      formData.append('image', file);

      const response = await fetch('/api/postImage', {
        method: 'POST',
        body: formData,
      });
      
      if (response.ok) {
        console.log('图片上传成功!');
        const imageUrl = await response.json();
        console.log('图片URL:', imageUrl);
      } else {
        console.error('图片上传失败');
      }
    } catch (error) {
      console.error('上传错误:', error);
    }
  };

  return (
    <>
      <input type="file" accept="image/jpeg" onChange={handleFileChange} />
      <button onClick={uploadImage} disabled={!file}>上传图片</button>
    </>
  );
};

2. API路由代码修改

使用formidable解析FormData,获取正确的文件二进制和原生Content-Type:
首先安装依赖:

npm install formidable

然后修改API路由:

import { NextApiRequest, NextApiResponse } from 'next';
import formidable from 'formidable';
import fs from 'fs';
import azureStorage from '../../app/lib/azureConnection';

export const config = {
  api: {
    bodyParser: false, // 禁用内置bodyParser,改用formidable解析
  },
};

export async function postImage(req: NextApiRequest, res: NextApiResponse) {
  try {
    const form = formidable({});
    const [fields, files] = await form.parse(req);
    
    const imageFile = files.image?.[0];
    if (!imageFile) {
      return res.status(400).json({ error: '未上传图片文件' });
    }

    const fileBuffer = await fs.promises.readFile(imageFile.filepath);
    const fileName = `example-${Date.now()}`; // 用时间戳避免文件名重复
    const imageUrl = await azureStorage.uploadImageToAzureStorage(
      fileBuffer,
      fileName,
      imageFile.mimetype // 使用文件原生的Content-Type
    );

    res.status(200).json(imageUrl);
  } catch (error) {
    console.error('上传处理错误:', error);
    res.status(500).json({ error: '服务器内部错误' });
  }
}

3. Azure存储函数优化

确保正确设置Content-Type,同时添加缓存控制头优化浏览器访问:

import { BlobServiceClient } from '@azure/storage-blob';

const connectionString = process.env.AZURE_CONNECTION;
const blobServiceClient = BlobServiceClient.fromConnectionString(connectionString as string);
const containerName = 'wilmascontainer';

async function uploadImageToAzureStorage(fileBuffer, fileName, contentType) {
  const containerClient = blobServiceClient.getContainerClient(containerName);
  const blockBlobClient = containerClient.getBlockBlobClient(fileName);
  
  const blobHTTPHeaders = {
    blobContentType: contentType,
    blobCacheControl: 'public, max-age=31536000' // 添加缓存控制,减少重复请求
  };

  await blockBlobClient.uploadData(fileBuffer, { blobHTTPHeaders });
  
  return blockBlobClient.url;
}

export default { uploadImageToAzureStorage };

额外检查项

  • 确认Azure Blob容器的访问级别确实是“Container”(允许匿名读取Blob和容器元数据);
  • 检查上传后的Blob属性,确认Content-Type已正确设置为image/jpeg;
  • 如果仍报400错误,检查Blob文件名是否包含特殊字符(如空格、中文等),建议使用英文字母、数字和横杠组合的文件名。

内容的提问来源于stack exchange,提问作者Tove Hydmark

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 03:17:26