nitro icon indicating copy to clipboard operation
nitro copied to clipboard

$fetch not working for internal urls with formData

Open Exotelis opened this issue 1 year ago • 1 comments

Environment

nitropack@latest node 16-22

Reproduction

https://stackblitz.com/edit/unjs-nitro-starter-xipb6m?file=server%2Froutes%2Findex.ts

Describe the bug

It seems that $fetch does not work with FormData on internal URLs. Here is an example on Stackblitz.

If you uncomment lines 12 to 15 and refresh the browser, you can clearly see the error. It seems that ofetch does not correctly serialize the data, and the application/x-www-form-urlencoded header is also not set properly. A workaround or potential fix is already included in the Stackblitz example.

Since the behavior of internal URLs is related to a Nitro feature and, as far as I know, is not yet part of ofetch, I am creating this bug report here because it likely needs to be fixed directly in Nitro.

Additional context

Potential fix:

// Works for both internal and external urls
const resFix = await $fetch('/test', {
  method: 'POST',
  body: formData,
  onRequest({ options, request }) {
    if (options.body instanceof FormData && request.startsWith('/')) {
      const params = new URLSearchParams();
      for (const [key, value] of options.body.entries()) {
        params.append(key, value);
      }

      options.headers = options.headers || new Headers();
      // Header is also missing when calling internal url!!!
      options.headers.set('Content-Type', 'application/x-www-form-urlencoded');
      options.body = params.toString();
    }
  },
});

Logs

[nitro] [request error] [unhandled] Request.formData: Could not parse content as FormData.
  at o.errors.exception (https://unjsnitrostarterxipb6m-dyvd.w-credentialless-staticblitz.com/builtins.ddb8d84d.js:93:35885)  
  at _Request.formData (https://unjsnitrostarterxipb6m-dyvd.w-credentialless-staticblitz.com/builtins.ddb8d84d.js:93:90813)  
  at async Module.readFormData (./node_modules/h3/dist/index.mjs:600:10)  
  at async Object.eval [as handler] (./.nitro/dev/index.mjs:970:20)  
  at async Object.eval [as handler] (./node_modules/h3/dist/index.mjs:2103:19)  
  at async toNodeHandle (./node_modules/h3/dist/index.mjs:2395:7)  
  at async ufetch (./node_modules/unenv/runtime/fetch/index.mjs:28:17)  
  at async $fetchRaw2 (./node_modules/ofetch/dist/shared/ofetch.03887fc3.mjs:275:26)  
  at async $fetch2 (./node_modules/ofetch/dist/shared/ofetch.03887fc3.mjs:333:15)  
  at async Object.eval [as handler] (./.nitro/dev/index.mjs:928:3)
[nitro] [request error] [unhandled] [POST] "/test": 500 
  at async $fetch2 (./node_modules/ofetch/dist/shared/ofetch.03887fc3.mjs:333:15)  
  at async Object.eval (./.nitro/dev/index.mjs:928:3)

Exotelis avatar Nov 15 '24 10:11 Exotelis

This is an issue with h3@1, you can track it here: https://github.com/unjs/h3/pull/1005 ❤️

kricsleo avatar Apr 01 '25 15:04 kricsleo