Touffy / client-zip

A client-side streaming ZIP generator

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[FEATURE] Specify attachment filename

ikreymer opened this issue · comments

Is your feature request related to a problem? Please describe.
It would be useful to be able to set a custom attachment filename through the Content-Disposition header.

Why is your feature relevant to client-zip?
Makes it easier for downloading zip files with a custom filename.

Describe the solution you'd like
Can add filename to the options and then in downloadZip and then its a one-line change:

  const headers: Record<string, any> = { "Content-Type": "application/zip", "Content-Disposition": options.filename ? `attachment; filename="${options.filename}"` : "attachment" }

Describe alternatives you've considered
It's possible to work around this currently by creating a new response, but is a bit more cumbersome to do:

    let response = downloadZip(zip);
    const headers = {
      "Content-Disposition": `attachment; filename="${filename}"`,
      "Content-Type": "application/zip"
    };

    response = new Response(response.body, {headers});
    return response;

Hello Ilya. Thank you for posting the issue.

I don't have a strong objection to this. It's a very small addition and would work exactly as you said. You might have written your suggestion as a PR directly. I'll add it if you insist.

There is, however, a way to accomplish the same result that is just as easy and doesn't require a new version of client-zip : set the filename in the download attribute of the link (to a Blob URL or a Service Worker, works either way).

<a href="link/to/the/archive.zip" download="filename.zip">download</a>

If the Zip file is meant to be downloaded by the client, download should do the trick. Unless you're using a <form> as I do in my Service Worker example, where I allow any URL starting with the right prefix to be intercepted. That way, you can set the filename by changing the form's action URL (my demo doesn't actually do that). I'll grant you it's not as obvious as the download attribute, but it is just as simple.

If the Zip file is meant to be sent to a server (it seems to be a thing that people do with client-zip too…), you can't use the Response anyway, you'll have to make a Request instead with the same body.

Thanks for the quick reply! In my case, the download is from a fixed service worker api endpoint, eg /api/.../dl. The way the system is setup, the service worker knows the best default filename, but you're right, it could also be set as the download attribute with a link. At present, I'm using a button and then setting: window.location.href = "/api/.../dl"
So yes, there are definitely workarounds, just thought it'd be a nice simple addition, but certainly not urgent.

I see. Hadn't considered that the Service Worker might have the logic to set the filename and not the client page, then it's easier to use the Content-Disposition header. Alright. You want to make the PR ?

BTW, setting window.location after a button click is not ideal for triggering a download — using a download link to that URL, even without a filename, lets the user (and the user agent) know that it's a download link using standard HTML semantics. You could still run some JavaScript when that link is clicked, if necessary.

FWIW files downloaded with the download attribute don't flow through service workers in chrome. So using the download attribute is not a good solution until that bug in chrome is closed (and it's been open for a long time and doesn't look to be prioritized so I wouldn't hold my breath 😄 )

Also fwiw you don't need the download attribute to specify the file name, I'm working around the above by using a _blank target i.e. <a href='/foo/bar.zip' target='_blank' />, which isn't ideal but that way errors in the service worker don't cause a redirect on the main page. But in any case, with that approach the download file is named bar.zip even without a Content-Disposition including a filename. So I just added a route segment and some query params that tell my service worker what it needs for getting the zip, and my service worker ignores the filename in the path entirely.

And here I thought Safari was behind Chrome on that issue… but Safari already fixed their ServiceWorker download problem (which was worse than Chrome's, TBH).

Chrome bug aside, the download attribute is useful even without a filename, preventing the browser from navigating when the link is clicked. And in this instance (without overhauling the design), Ilya can use neither the href or download attributes to set the filename because the filename logic is in his ServiceWorker, and the only simple way for the ServiceWorker to pass that information is the Content-Disposition header.