Node.js中IPFS文件上传Async/Await问题:无法获取文件Hash
Hey there! I see you're stuck trying to pull that proper IPFS hash when uploading files via Node.js—let's break down what's going wrong with each of your attempts and fix this once and for all.
What's Off with Each Approach?
1. Initial Async/Await Code
Your first try uses await ipfs.add(...) and tries to access fileAdded[0].hash, but here's the catch:
- Modern versions of
ipfs-http-client'saddmethod returns an AsyncIterable (not a promise that resolves to an array). When youawaitan AsyncIterable, you only get the first item in the sequence, not an array. SofileAddedis a single file object, not an array—hencefileAdded[0]isundefined, causing your "hash undefined" error.
2. Callback + Async/Await Hybrid
Mixing callbacks with async/await here creates a mess:
- When you pass a callback to
ipfs.add, it doesn't return a promise, soawaitdoes absolutely nothing. ThefileAddedvariable will always beundefinedbecause the callback's result never gets assigned to it. - The
return fileHashinside the callback only exits the callback function, not the outeraddFileasync function. That's why you never get a hash back from this method.
3. For-Await Loop Version
This approach is actually almost right! The problem is likely how you're using the returned value:
- You're returning an array of hashes (
hashes), but if you're uploading a single file, you only need the first element of that array. If you're passing the entire array to your EJS template without grabbingfileh[0], you won't get the clean hash string you're expecting.
The Fixed Solution
Let's refine the for-await loop approach to return the exact single hash you need, and make sure the rest of your code handles it correctly.
Updated addFile Function
const addFile = async (Name, filePath) => { const file = fs.readFileSync(filePath); // Iterate over the AsyncIterable from ipfs.add for await (const result of ipfs.add({ path: Name, content: file })) { // Since we're uploading one file, return the first hash immediately return result.hash; } // Fallback in case no result is returned (unlikely for valid files) throw new Error("Failed to retrieve file hash"); };
Adjusted Route Handler
Make sure when you call addFile, you're getting the clean hash string and handling errors gracefully:
app.post('/upload',(req,res)=>{ const f = req.files.file; const Name = req.files.file.name; const filePath = "files/"+ Name; f.mv(filePath, async(err)=>{ if(err){ console.log("Error saving file locally:", err); return res.status(500).send(err); } try { const fileh = await addFile(Name, filePath); fs.unlink(filePath, (err)=>{ if(err) console.log("Error deleting local file:", err); }); // Now fileh is the single hash string you want (e.g., QmRndAYkvH3D2qhmYfaAZvWT6MDi4NiJPbzJor3EL87rrb) res.render('upload',{Name, fileh}); } catch (error) { console.log("Error adding file to IPFS:", error); res.status(500).send("Failed to upload file to IPFS"); } }); });
Key Takeaways
- AsyncIterable Handling: Always use a
for await...ofloop with modernipfs.addcalls—it streams results, which is also useful for multiple files or large datasets. - Error Handling: Added
try/catcharound theaddFilecall to catch any IPFS-related issues gracefully instead of letting them crash your app. - Cleanup: Improved local file deletion logging to make debugging easier if something goes wrong there.
This should give you the exact hash format you're looking for to pass to your EJS template.
内容的提问来源于stack exchange,提问作者norah

