Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Only clone response on retries, not first try? #435

Open
veltman opened this issue Apr 14, 2022 · 5 comments
Open

Only clone response on retries, not first try? #435

veltman opened this issue Apr 14, 2022 · 5 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@veltman
Copy link

veltman commented Apr 14, 2022

Related to #231, it seems like ky clones the request before every fetch so that a retry with a POST body works. But this continues to prevent using ky in cases where a POST gets proxied by something like Puppeteer or Playwright because of the underlying bug in the DevTools Protocol (which might never get fixed).

If I'm understanding the status quo correctly, would there be any downside to only cloning the request on the retry attempts and not on the initial fetch? It seems like that could at least solve the problem for requests that succeed without a retry. If that seems reasonable to you I could work up a PR for it...

@sholladay
Copy link
Collaborator

sholladay commented Apr 17, 2022

It's been a while since I took a hard look at the request cloning mechanics, but I don't believe this will work.

Any time we pass a Request instance to fetch(), it consumes the request body, meaning that the request cannot be reused because the request body can never be read more than once. Thus, we have to preemptively clone the request and pass in the cloned copy to fetch() if we ever want to be able to reuse the original request instance in the future (as would happen in the case of a retry).

So, if the first fetch() gets a request that hasn't been cloned, it will consume the body and prevent any retries.

I'm open to suggestions, but don't currently see a way to make this workable. request.clone() is a real PITA.

@veltman
Copy link
Author

veltman commented Apr 18, 2022

But am I correct that you could preemptively clone the request for the future usage, and then consume the uncloned request? That way on the first fetch attempt, you'd be using the uncloned request but still be able to use the clone in the event of a retry.

i.e. in pseudocode:

async function fetchAttempt(request) {
  const clone = request.clone();
  const response = await fetch(request);
  if (shouldRetry(response)) {
    return fetchAttempt(clone);
  } else {
    return response;
  }
}

@sholladay
Copy link
Collaborator

Ah, yes, I quite like that and it should work. At the time of #231, Deno had an implementation bug where calling clone() would consume the original request's body, so we had to pass in the clone and not the original, plus it simplified the code a bit. But that bug has been fixed since then. I also just checked node-fetch and even its clone() implementation seems to behave properly in this respect.

If you'd like to open a PR, that would help a lot.

@sindresorhus sindresorhus added enhancement New feature or request help wanted Extra attention is needed labels Jun 2, 2022
@ulken
Copy link
Contributor

ulken commented Feb 1, 2023

Given this, is this something you still want to pursue? I'm hit by the same problem and would be willing to have a stab at it. But I'd like you to sign off on it first. If not, should this be closed?

@sholladay
Copy link
Collaborator

This is still a valid improvement. Cloning requests is error prone, see e.g. #209. It would be nice to use the original request for the initial fetch attempt to avoid any cloning bugs where cloning isn't needed..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

4 participants