Search code examples
node.jsexpressaxiosxmlhttprequestmultipartform-data

Is it possible to detect an immediate when sending a chunky POST request with AXIOS


I am using AXIOS in a web client in order to POST a file to the express backend as an upload. Since both the file's size and the client user's bandwidth is variable, it may take a certain amount of time for the POST request to finish. On the backend some logic applies and the request is promptly rejected.

The problem is that the client receives the response only after the request is finished, which can be several seconds.

I have already tested that it is not the backend's fault, as the behavior is the same when POSTing to any arbitrary post-enabled url in the web, regardless of the technology. Here is an (over)simplified example of the case.

Here's the post action. Notice the commended request to the arbitrary post-enabled url. It behaves exactly the same:

try{
    console.log("posting....")
    const res = await axios.post("http://localhost:4000/upload", formData)
    // const res = await axios.post("https://github.com/logout", formData)
    console.log("result:")
    console.log(res)
}catch(err){
    console.error(err)
}

And the demo express backend route:

app.post("/upload", (req, res) => {
    console.log("Rejecting...")
    res.status(403).send()
    console.log("Rejected.")
    return
})

For testing purposes I choose a 3.7Mb file, and throttle down my browsers bandwidth to the Fast 3G preset.

The backend immediately outputs:

Rejecting... Rejected.

Whereas the request is pending for about 43 seconds before returning the 403 error:

devtools request inspection

Am I missing something obvious here? It is such a common functionality, it makes me doubt that this is the correct way to be handled. And if it really is, do we have any information on whether express's thread is active during that time, or is it just a client inconvenience?

Thanks in advance!


Solution

  • It seems that first sending the response headers and then manually destroying the request does the trick:

    app.post("/upload", (req, res) => {
        console.log("Rejecting...")
        res.status(403).send("Some message")
        return req.destroy()
    })
    

    The AXIOS request stays pending until just the current chunk is uploaded, and then immediately results in the correct status and message. In the throttled down fast 3g example, pending time went down from 43s to 900ms.

    Also, this solution emerged through trial and error, so it can possibly not be the best practice.

    I would still be interested in an AXIOS oriented solution, if one exists.