在Next.js中使用formidable时没有任何反应

问题描述 投票:0回答:1

我想做的是将文件从前端上传到我的 GCP 工作流程,并且它正确地执行了此操作,但是我不断遇到

API resolved without sending a response
问题。我尝试将
form.parse()
放入
Promise
中,但这也不能有效地为我返回响应。让我更困惑的部分是我在前端控制台记录响应,如果成功,它会正确显示响应。以下是我当前的代码:

export const config = {
  api: {
    bodyParser: false
  }
}

export default async function handler(req, res) {
  const { query: { uuid } } = req
  const token = await getToken({ req })
  const key = JSON.parse(process.env.GOOGLE_APPLICATION_CREDENTIALS.toString())

  if (!token) {
    return res.status(401).json({ error: 'User must be logged in to perform this action' })
  }

  const storage = new Storage({
    projectId: process.env.PROJECT_ID,
    credentials: {
      client_email: key.client_email,
      private_key: key.private_key.replace(/\\n/g, '\n')
    }
  })

  const form = formidable({
    keepExtensions: true,
  })

  form.parse(req, async (error, fields, files) => {
    if (error) {
      console.error(`Error parsing form: ${error}`);
      return res.status(500).json({ error: 'Error parsing form' });
    }

    const selectedFile = files.file[0];
    if (!selectedFile) {
      console.error('No file uploaded')
      return res.status(400).json({ error: 'No file uploaded' })
    }

    const salt = crypto.randomBytes(16).toString('hex')
    const hashedFilename = crypto.createHash('sha256').update(selectedFile.originalFilename + salt).digest('hex')

    const bucket = storage.bucket(process.env.CLOUD_STORAGE_BUCKET_NAME)
    const blob = bucket.file(hashedFilename)

    const blobStream = createReadStream(selectedFile.filepath)
      .pipe(blob.createWriteStream({
        resumable: false,
        contentType: selectedFile.mimetype
      }))

    blobStream.on('error', (error) => {
      console.error(`Error uploading files to cloud storage: ${error}`)
      cleanupStreams(blobStream, selectedFile.filepath)
      return res.status(500).json({ error: 'Error uploading files to cloud storage' })
    })

    blobStream.on('finish', async () => {
      try {
        await blob.setMetadata({
          metadata: {
            UUID: uuid,
            FILE_NAME: selectedFile.originalFilename,
            CREATION_DATE: getDate(),
          }
        })

        cleanupStreams(blobStream, selectedFile.filepath)
        return res.status(201).json({ message: `Uploaded the file successfully: ${selectedFile.newFilename}` })
      } catch (error) {
        console.error(`Error setting metadata: ${error}`)
        cleanupStreams(blobStream, selectedFile.filepath)
        return res.status(500).json({ error: 'Error setting metadata' })
      }
    })
  })

  form.on('error', (error) => {
    console.error(`Form parsing error: ${error}`)
    return res.status(500).json({ error: 'Error processing form data' })
  })
}
javascript reactjs node.js next.js
1个回答
0
投票

您所面临的问题(API 在不发送响应的情况下解决)可能与异步操作中响应的管理方式有关。更具体地说,问题可能源于文件上传和元数据设置的异步处理,这可能无法有效地向 Next.js 发出请求完成的信号。

您可以采取以下几个步骤来解决此问题👇

👉 确保完整的响应处理:在 Node.js 和 Next.js 中,必须确保函数的每个潜在执行路径都以

res.send()
res.json()
res.end()
结束。您当前的实现可能缺少在某些异步分支中发出响应结束信号的信号。

👉 管理异步操作:利用 Promise 或 async/await 可以促进异步操作的更清晰管理。这可能意味着将表单解析和后续操作封装在 Promise 中,并使用 async/await 处理这些操作。

👉 使用 Async/Await 进行重构以实现更好的流程控制:重构处理程序函数以利用 async/await 来改进控制流管理可能是有益的。尝试下面更新的处理函数👇

export const config = {
  api: {
    bodyParser: false
  }
}

export default async function handler(req, res) {
  const { query: { uuid } } = req;
  const token = await getToken({ req });
  const key = JSON.parse(process.env.GOOGLE_APPLICATION_CREDENTIALS.toString());

  if (!token) {
    return res.status(401).json({ error: 'User must be logged in to perform this action' });
  }

  const storage = new Storage({
    projectId: process.env.PROJECT_ID,
    credentials: {
      client_email: key.client_email,
      private_key: key.private_key.replace(/\\n/g, '\n')
    }
  });

  try {
    const data = await new Promise((resolve, reject) => {
      const form = formidable({ keepExtensions: true });
      form.parse(req, (error, fields, files) => {
        if (error) {
          reject({ status: 500, error: 'Error parsing form' });
        } else {
          resolve(files);
        }
      });
    });

    const selectedFile = data.file[0];
    if (!selectedFile) {
      return res.status(400).json({ error: 'No file uploaded' });
    }

    const salt = crypto.randomBytes(16).toString('hex');
    const hashedFilename = crypto.createHash('sha256').update(selectedFile.originalFilename + salt).digest('hex');
    const bucket = storage.bucket(process.env.CLOUD_STORAGE_BUCKET_NAME);
    const blob = bucket.file(hashedFilename);
    const blobStream = createReadStream(selectedFile.filepath)
      .pipe(blob.createWriteStream({
        resumable: false,
        contentType: selectedFile.mimetype
      }));

    blobStream.on('error', error => {
      console.error(`Error uploading files to cloud storage: ${error}`);
      return res.status(500).json({ error: 'Error uploading files to cloud storage' });
    });

    await new Promise((resolve, reject) => {
      blobStream.on('finish', resolve);
      blobStream.on('error', reject);
    });

    await blob.setMetadata({
      metadata: {
        UUID: uuid,
        FILE_NAME: selectedFile.originalFilename,
        CREATION_DATE: new Date().toISOString(),
      }
    });

    return res.status(201).json({ message: `Uploaded the file successfully: ${selectedFile.originalFilename}` });
  } catch (error) {
    console.error(error);
    return res.status(500).json({ error: error.message || 'An error occurred' });
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.