无法将FormData从Nextjs API发送到Next.js后端(错误405:错误请求)

n3schb8v  于 12个月前  发布在  其他
关注(0)|答案(3)|浏览(138)
  • 已解决/请参阅我自己的答案,以获取更多信息 *

嘿,我得到了这个非常奇怪的错误,我似乎无法弄清楚它。所以基本上我试图发送一个音频记录,用户记录在我的Nextjs前端,到我的Nextjs API。这似乎是顺利的。但是,当我试图转发整个录音从我的Nextjs API到我的实际后端端点,这是运行节点/Node. js在Vercel上,我得到了一个405错误的请求。有什么想法吗?

重要提示:在localhost上一切正常。但当我在Vercel上将其投入生产时就不正常了。(客户端和服务器端都是在Vercel上运行的Node应用。一个是Nextjs,一个稍旧的版本,服务器端是Express)
出于安全原因,我使用Next.js作为中间的API

到目前为止,我唯一的理论是“formData.append”不能正常工作,因为每当我试图将其或其全部内容记录出来时,我总是得到一个空白对象:{}
这里:

const formDataToSend = new FormData()

 formDataToSend.append(fileName, new Blob([readResult], { type: 'audio/wav' }), `${fileName}.wav`)

字符串
(full代码如下所示)
Nextjs version:13.5.4 Nextjs version:4.18.2
EXPRESS.JS代码:

app.use(cors()) 

const storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, '/tmp/') 
  },
  filename: function (req, file, cb) {
    cb(null, `${file.originalname}`)
  }
})

const upload = multer({ storage: storage })

...

app.post('/upload', [requireSession, upload.any()], async (req, res) =>
{
  // the request never even gets here in the first place
  // requireSession works fine
})


NEXT.JS API:

import { csrf } from '../../../../lib/csrf'
import axios from 'axios'
import crypto from 'crypto'
import multiparty from 'multiparty'
import fs from 'fs'

// valid url
const ENDPOINT_URL = 'https://my-api.com/upload'

// works fine
async function readAudioFile(filePath) {
  return new Promise((resolve, reject) => {
    const readStream = fs.createReadStream(filePath)
    const chunks = []
    readStream.on('data', (chunk) => {
      chunks.push(chunk)
    })
    readStream.on('end', () => {
      const fileBuffer = Buffer.concat(chunks)
      resolve(fileBuffer)
    })
    readStream.on('error', (err) => {
      reject(err)
    })
  })
}

async function post(req, res)
{
  try {
    // works fine
    const form = new multiparty.Form()

    // works fine
    const formData = await new Promise((resolve, reject) => {
      form.parse(req, function (err, fields, files) {
        if (err) reject({ err })
        resolve({ fields, files })
      })
    })

    // works fine
    const readResult = await readAudioFile(formData.files.audio[0].path)

    // works fine
    const randomizer = `${req?.headers?._uuid}-${req?.query?.taskId}-${(new Date().getTime()).toString(16)}`

    // works fine
    const fileName = crypto.createHash('sha256').update(randomizer).digest('hex')

    // works fine
    const formDataToSend = new FormData()

    // !! Not sure. when i log em out, "formDataToSend" and "formDataToSend.entries()" are both empty. (Just a "{}")
    formDataToSend.append(fileName, new Blob([readResult], { type: 'audio/wav' }), `${fileName}.wav`)

    // Nothing undefined here, works fine
    const headers = { 
      'client': process.env.API_ACCESS_KEY, 
      '_session': req.headers._session,
      '_uuid': req.headers._uuid,
      ...req.headers,
      'Content-Type': 'multipart/form-data', 
      'Request-Index': '0' ,
    }
  
    // this request fails with code 405
    await axios.post(ENDPOINT_URL, formDataToSend, { headers, params: { ...req.query } })
    .then(response => (res.status(200).json(response.data)))
    .catch(error => (console.log(error), res.status(500).json({
      ...getErrorMessage(),
      errorDetails: error,
      dataToSend
    })))
  }
  catch (error) {
    console.log(error)
    res.status(501).json({
      ...getErrorMessage(),
      errorDetails: error,
      dataToSend
    })
  }
}

async function handler(req, res) 
{
  switch (req.method.toLowerCase())
  {
    case 'post':
      await post(req, res)
      break
    default:
      res.status(200).send(`Method ${req.method} is not allowed.`)
      break
  }
}

const getErrorMessage = () => { return { time: Date.now(), result: false, status: 500, message: 'Something went wrong' } }

export default csrf(handler)

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


我已经尝试了几乎所有我能想到的方法。包括使用fetch而不是axios,扰乱我express.js端点的CORS设置等。我认为问题出在FormData上。不过在localhost上运行良好

vmjh9lq9

vmjh9lq91#

既然Vercel是无服务器计算提供商,我认为你应该尝试将你的Web应用程序部署到其他平台上。
您也可以阅读:https://vercel.com/guides/using-express-with-vercel
如果成功了告诉我。

4c8rllxm

4c8rllxm2#

谢谢你们的帮助。我是这样解决的:
改变了这个:

const headers = { 
      'client': process.env.API_ACCESS_KEY, 
      '_session': req.headers._session,
      '_uuid': req.headers._uuid,
      ...req.headers,
      'Content-Type': 'multipart/form-data', 
      'Request-Index': '0' ,
    }

字符串
对此:

const headers = { 
  'client': process.env.API_ACCESS_KEY, 
  '_session': req.headers._session,
  '_uuid': req.headers._uuid,
  'Content-Type': 'multipart/form-data', 
  'Request-Index': '0' ,
}


显然我忘了删除一行干扰请求头的代码。在浪费了几个晚上试图让这件事工作后,我才意识到这是怎么回事。我真傻!

lmyy7pcs

lmyy7pcs3#

换了这个试试

formDataToSend.append(fileName, new Blob([readResult], { type: 'audio/wav' }), `${fileName}.wav`)

字符串

.append() // doesn't take any third parameter

formDataToSend.append(fileName, new Blob([readResult], { type: 'audio/wav' }))

相关问题