Scenario
We are building a UI that allows users to query our data in bulk. The return format is CSV and there is a decent amount of processing that needs to happen, so this processing processing is done in parallel and then sets of rows are streamed back to the UI.
Current Implementation
An AJAX POST request is sent to the server, it waits for all of the data to come in and then uses createObjectURL
to trigger a download. The issue is that it can take several minutes for the request to complete and the user sees a spinning indicator indicating that their request is in progress.
Problem
It's a bad experience that the user cannot see any other progress and has no idea whether their request is actually processing or how long it will take.
Goal
To have the browser download the file as it's being streamed back to the client.
Obstacle
It does not seem possible to enable this behavior in JavaScript. The closest that I found was a script StreamSaver.js but using an external MITM is not acceptable and I don't understand the code well enough to determine whether this is a viable (or even good approach).
Other Ideas
Use a GET request or a form. The issue here is two-fold: (1) The request data can be nested and of variable length. It doesn't seem right to have to be parsing a request string on the backend. (2) It seems like this causes a page reload, which kills the state of the React application.
Instead of downloading the file continuously on the client, we can add a progress bar instead. To be this, we could add a header to the response indicating how many chunks are expected and then increment when each chunk is received. The downside of this approach is that the user cannot cancel the request and they cannot recover partial results.
Help
It feels like I'm missing a much better solution to this issue. Please feel free to challenge any of the assumptions above. My main goal is to get a clean solution that provides a good user experience.
Notes
The backend is a C# web application, React is being used on the front-end, and it's possible to pipe through a PHP layer if somehow that would help.
PushStreamContent
to stream the file back to the client, but there is no way to download a stream from an AJAX request in JavaScript.