sindresorhus / ky

🌳 Tiny & elegant JavaScript HTTP client based on the Fetch API
MIT License
11.91k stars 342 forks source link

Sending form data fails on Deno 1.13.2 #380

Open mt-u opened 2 years ago

mt-u commented 2 years ago

Hi. I get an error when I send form data using ky.post method on Deno 1.13.2. Error message is below:

error: Uncaught (in promise) TypeError: Unreachable
    at mainFetch (deno:ext/fetch/26_fetch.js:190:33)

It is no problem on Deno 1.11.5. But on Deno 1.13.2, it fails. Even though raw fetch (globalThis.fetch) succeeds. ky.post with json also succeeds.

There may be some discrepancies between what your library expects and the latest Deno implementation.

I tried using a Deno Docker container. The command used is:

docker run -v /[path-to-dir-includes-my-sample-file]:/tmp/test -it --rm denoland/deno:debian-1.13.2 run --unstable -A /tmp/test/my-sample.ts  

This is my sample code:

// my-sample.ts
import ky from 'https://cdn.skypack.dev/ky?dts';

// prepare parameters
const url = 'https://example.com';
const json = { hoge: 'hoge' };
const formData = new FormData();
formData.append('hoge', 'hoge');

// Deno's raw fetch post with FormData
console.log('\nTry fetch post.');
let r = await fetch(url, { method: 'POST' , body: formData });
console.log('Success? :', r.ok);

// ky post with JSON
console.log('\nTry ky post with JSON.');
r = await ky.post(url, { json: json });
console.log('Success? :', r.ok);

// ky post with FormData
console.log('\nTry ky post with FormData.');
r = await ky.post(url, { body: formData }); // will fail
console.log('Success? :', r.ok);

results:


Try fetch post.
Success? : true

Try ky post with JSON.
Success? : true

Try ky post with FormData.
error: Uncaught (in promise) TypeError: Unreachable
    at mainFetch (deno:ext/fetch/26_fetch.js:190:33)
sholladay commented 2 years ago

I am able to reproduce. I bisected the Deno version and found that Deno 1.12.0 is where it breaks.

The error message points to this line in Deno's code:

https://github.com/denoland/deno/blob/1563088f060b1f1d4826bb3a6d4120b276a4e15f/ext/fetch/26_fetch.js#L178

So I guess the request URL is being turned into a Blob URL somehow? Not sure why that would be happening. We're certainly not doing that intentionally and given that we're not having this problem in other environments or on older versions of Deno, I'm inclined to say this should be reported to the Deno team as a regression. But it's possible we're doing something funky - needs more investigation.

Repro code:

import ky from 'https://cdn.skypack.dev/ky?dts'

const url = 'https://httpbin.org/anything';
const body = new FormData();
body.append('username', 'janedoe');
// const response = await fetch(url, { method : 'POST', body });
const response = await ky.post(url, { body });

console.log('response:', response);
console.log('form:', (await response.json()).form);
pethin commented 11 months ago

I found that wrapping the form data in a URLSearchParams works.

const url = 'https://example.com';
const formData = new FormData();
formData.append('username', 'test');

r = await ky.post(url, { body: new URLSearchParams(formData) });
gera2ld commented 9 months ago

It's caused by https://github.com/denoland/deno/issues/16570 , fetch(request.clone()) does not work in Deno when there is a stream body.

https://github.com/sindresorhus/ky/blob/577dd4c5e36f214930a22247523a73d37847c335/source/core/Ky.ts#L298

sholladay commented 3 weeks ago

Is this still happening with latest Ky and Deno?

435 may improve the situation, at least for requests that aren't retried.