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

如何在Hapi.js中上传并保存文件/图片?求推荐适用工具包

Hey there! Let's break down how to handle file uploads and saving in Hapi.js based on your code and questions.

Hapi.js: Uploading and Saving Files/Images

1. Your Upload Configuration is Already Correct

First off, the payload setup in your POST /company endpoint is spot-on for handling file uploads:

  • maxBytes: 20715200: Limits uploads to 20MB (perfect for most logos/files)
  • output: "stream": Treats uploaded files as Node.js streams, which is ideal for efficient saving
  • parse: true: Automatically parses the multipart form data, so you can access text fields like companyName and file streams like logo directly from request.payload
  • allow: "multipart/form-data": Allows the multipart form format required for file uploads

No changes needed here—you’ve got the upload part covered!

2. Saving Files: Use Node.js Native fs Module (No Extra Dependencies!)

You don’t need any fancy third-party packages for saving files. Node.js built-in fs (file system) module is more than enough. Here’s how to modify your handler to save the logo:

First, add these imports at the top of your file:

const fs = require('fs').promises; // Promise-based fs for async/await
const path = require('path');

Then update your handler to an async function (since file operations are asynchronous):

handler: async (request, h) => {
  const { companyName, logo } = request.payload;

  try {
    // Define where you want to save the logo (e.g., ./uploads/logos)
    const uploadDirectory = path.join(__dirname, 'uploads', 'logos');
    
    // Create the directory if it doesn't exist (recursive: true makes parent folders too)
    await fs.mkdir(uploadDirectory, { recursive: true });

    // Generate a unique filename to avoid overwriting existing files
    const uniqueFileName = `${Date.now()}-${logo.hapi.filename}`;
    const fullSavePath = path.join(uploadDirectory, uniqueFileName);

    // Pipe the uploaded file stream to a write stream
    await new Promise((resolve, reject) => {
      const writeStream = fs.createWriteStream(fullSavePath);
      logo.pipe(writeStream);

      // Resolve when the file finishes writing
      writeStream.on('finish', resolve);
      // Reject if there's an error writing the file
      writeStream.on('error', reject);
    });

    // Optional: Save the file path to your database alongside companyName
    // Example: await db.companies.create({ name: companyName, logoPath: fullSavePath });

    return h.response({
      message: 'Company created successfully!',
      company: {
        name: companyName,
        logoUrl: `/uploads/logos/${uniqueFileName}` // For frontend access
      }
    }).code(201); // 201 = Created status code

  } catch (error) {
    console.error('Error saving file or creating company:', error);
    return h.response({ error: 'Failed to create company' }).code(500);
  }
}

Key Details:

  • logo.hapi.filename: Hapi adds this property to the file stream, giving you the original name of the uploaded file
  • Date.now() prefix: Ensures filenames are unique, so you don’t accidentally overwrite existing logos
  • fs.mkdir({ recursive: true }): Automatically creates all parent directories if they don’t exist (no need to manually check each folder)
  • Promise wrapper around pipe: Since streaming is asynchronous, we wait for the write operation to finish before sending a response

3. Optional: Restrict File Types

If you want to limit uploads to specific file types (e.g., only images), add an allowed array to your payload config:

payload: {
  maxBytes: 20715200,
  output: "stream",
  parse: true,
  allow: "multipart/form-data",
  allowed: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'] // Only allow image files
}

Hapi will automatically reject files that don’t match these MIME types and return a 415 Unsupported Media Type error.

4. Bonus: Better Error Handling with @hapi/boom (Optional)

For more consistent error responses, you can use the @hapi/boom package to create standard HTTP errors:

  1. Install it first:
npm install @hapi/boom
  1. Update your catch block:
const Boom = require('@hapi/boom');

// ...

catch (error) {
  console.error('Error:', error);
  throw Boom.internal('Failed to create company', error);
}

Hapi will automatically convert Boom errors into properly formatted HTTP responses with the correct status codes.

内容的提问来源于stack exchange,提问作者Shringiraj Dewangan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 19:52:36