Azure部署BotFramework时从Buffer写文件遇InternalServerError问题
Hey there, let's break down why your receipt bot is throwing that ENOENT error on Azure and how to fix it quickly.
The Root Cause
Your local development environment lets you write files directly to your project's wwwroot directory because you have full filesystem permissions there. But Azure App Service sets the D:\home\site\wwwroot directory as read-only by default—so any attempt to write files there will fail with a "no such file or directory" error, even if the path looks correct.
Additionally, your current code uses the asynchronous fs.writeFile without waiting for it to complete, which could lead to race conditions, but the main culprit here is the read-only filesystem restriction.
Solutions
We have two solid options here—one for temporary testing, and one for production-ready persistent storage.
Option 1: Use Azure's Temporary Storage (Quick Testing Fix)
Azure provides a writable temporary directory at D:\local\Temp (you can also access it via the TEMP environment variable). This works for quick tests, but note that all files here will be deleted when your app restarts or scales.
Update your path logic to use this directory, and switch to the promise-based file write to ensure completion:
// Update the path to use temporary storage const localFileName = path.join(process.env.TEMP || 'D:\\local\\Temp', attachment.name); // Replace fs.writeFile with promise-based version to wait for completion await fs.promises.writeFile(localFileName, response.data);
Option 2: Use Azure Blob Storage (Production-Grade)
For a persistent solution (since you need to keep receipts to submit to your accounting API), Azure Blob Storage is the right choice—it's designed for storing unstructured data like images and integrates seamlessly with App Service.
- Install the Azure Storage SDK:
npm install @azure/storage-blob
- Update your
handleReceiptsfunction to use Blob Storage instead of local files:
const { BlobServiceClient } = require('@azure/storage-blob'); const path = require('path'); const axios = require('axios'); async function handleReceipts(attachments) { const attachment = attachments[0]; const url = attachment.contentUrl; const blobName = attachment.name; // Get your storage connection string from Azure Portal (add to App Service env vars) const blobServiceClient = BlobServiceClient.fromConnectionString(process.env.AZURE_STORAGE_CONNECTION_STRING); const containerClient = blobServiceClient.getContainerClient('receipts'); // Ensure this container exists in your storage account try { const response = await axios.get(url, { responseType: 'arraybuffer' }); const blockBlobClient = containerClient.getBlockBlobClient(blobName); // Upload receipt to Blob Storage with correct content type await blockBlobClient.upload(response.data, response.data.length, { blobHTTPHeaders: { blobContentType: attachment.contentType } }); return `Successfully saved receipt: ${blobName}`; } catch (error) { console.error('Error saving receipt:', error); return undefined; } }
- Configure your storage connection string:
- Create an Azure Storage account and a container named
receipts(set appropriate access levels). - In the Azure Portal, go to your App Service → Configuration → Application Settings, add a new setting named
AZURE_STORAGE_CONNECTION_STRINGwith your storage account's connection string.
Quick Verification Checks
- Confirm your Azure App Service can access Blob Storage via the connection string (no extra permissions needed if using the full connection string).
- If using temporary storage, log the
localFileNameto ensure it points toD:\local\Tempinstead ofwwwroot.
内容的提问来源于stack exchange,提问作者Hessel

