next.js
next.js copied to clipboard
Middleware throws `TypeError` when trying to parse FormData
Verify canary release
- [X] I verified that the issue exists in Next.js canary release
Provide environment information
Operating System:
Platform: darwin
Arch: x64
Version: Darwin Kernel Version 21.4.0: Mon Feb 21 20:34:37 PST 2022; root:xnu-8020.101.4~2/RELEASE_X86_64
Binaries:
Node: 16.13.2
npm: 8.1.2
Yarn: 1.22.15
pnpm: N/A
Relevant packages:
next: 12.1.6-canary.9
react: 17.0.2
What browser are you using? (if relevant)
No response
How are you deploying your application? (if relevant)
No response
Describe the Bug
Not sure if I'm doing anything unexpected, but here goes:
request.formData()
- throws
While trying to parse FormData
in a middleware like so:
// pages/_middleware.ts
const handler = async (request: NextRequest, _nfe: NextFetchEvent) => {
const data = await request.formData();
};
export default handler;
With the following request (application/x-www-form-urlencoded
):
curl --request POST \
--url http://localhost:3000/foo \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data foo=bar
or (multipart/form-data
):
curl --request POST \
--url http://localhost:3000/foo \
--header 'Content-Type: multipart/form-data; boundary=---011000010111000001101001' \
--form foo=bar
Next throws the following error:
TypeError: Unrecognized Content-Type header value.
FormData can only parse the following MIME types: multipart/form-data, application/x-www-form-urlencoded.
request.json()
- works
Making a similar request but with JSON
, using the request.json()
-method everything works as expected.
curl --request POST \
--url http://localhost:3000/foo \
--header 'Content-Type: application/json' \
--data '{ "foo": "bar" }'
Expected Behavior
request.formData()
to parse and return the data for multipart/form-data
and application/x-www-form-urlencoded
To Reproduce
- Create a middleware in
pages/_middleware.ts
const handler = async (request: NextRequest, _nfe: NextFetchEvent) => {
const data = await request.formData();
};
export default handler;
- Make a request similar to one of these:
curl --request POST \
--url http://localhost:3000/foo \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data foo=bar
curl --request POST \
--url http://localhost:3000/foo \
--header 'Content-Type: multipart/form-data; boundary=---011000010111000001101001' \
--form foo=bar
- Next should throw the following error:
TypeError: Unrecognized Content-Type header value.
FormData can only parse the following MIME types: multipart/form-data, application/x-www-form-urlencoded.
Is anyone working on this? Can I? Thanks 🙏🏻
hey @nelodev, I am not sure if you have any progress with it, so I'm going to check this out :pray:
summary of #37980: a url encoded body does work, but multipart form data does not. it's blocked on undici/the edge-runtime library to implement this. :pray: lets do it
Is there any way to convert the x-www-form-urlencoded data to JSON data, similar to bodyParser.urlencoded?
related: https://github.com/nodejs/undici/issues/974
The latest Next.js canary should resolve this issue.
In fact, I built a little demo at https://with-edge.vercel.app/api/form-data :✨
// pages/api/form-data.ts
import { NextRequest, NextResponse } from 'next/server'
export const config = { runtime: 'experimental-edge' }
/**
* Original source
* https://gist.github.com/eligrey/8335f09276492e69b747fb4017e9570e
*
* Get the cryptographic hash of an ArrayBuffer
*
* @param ab - ArrayBuffer to digest
* @param algorithm - Cryptographic hash digest algorithm
* @returns Hexadecimal hash digest string
*/
export const hash = async (
algorithm: string,
ab: ArrayBuffer,
): Promise<string> =>
new Uint8Array(await crypto.subtle.digest(algorithm, ab)).reduce(
(memo, i) => memo + i.toString(16).padStart(2, '0'),
'',
);
const ENDPOINT = process.env.NODE_ENV === 'production'
? 'https://with-edge.vercel.app'
: 'http://localhost:3000'
export default async function handler(req: NextRequest) {
if (req.method === 'GET') {
return NextResponse.json({
description: 'Upload a file as multipart.',
usage: `curl -X POST ${ENDPOINT}/api/form-data -F "file=@/logo.png" | jq`
})
}
const formData = await req.formData()
const file = formData.get('file') as File
const arrayBuffer = await file.arrayBuffer()
return new Response(JSON.stringify({
name: file.name,
type: file.type,
size: file.size,
sha256: await hash('SHA-256', arrayBuffer),
sha1: await hash('SHA-1', arrayBuffer),
sha384: await hash('SHA-384', arrayBuffer),
sha512: await hash('SHA-512', arrayBuffer)
}))
}
Can you confirm is works for you using Next.js v12.3.2-canary.22
or above?
(if not, I will reopen the issue)
This closed issue has been automatically locked because it had no new activity for a month. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.