A few gotchas with the interaction between the
fetch APIs, for those used to
The browser wraps any Fetch or XHR request sending FormData
In a recent project, we needed to upload images to Rackspace Cloud Files from a form. After a bit of googling, we quickly arrived at code reminiscent of the following:
To our surprise, this caused a parsing error on Rackspace. Mysteriously, our image data was arriving at the server wrapped with
------WebKitFormBoundaryJ0uWMNv29fcUxC1t--, and Rackspace didn’t like that one bit.
According to StackOverflow, the conventional wisdom was to write some server-side code to parse out the
WebKitFormBoundary nonsense, but unfortunately we don’t control RackSpace and thus can’t control how how our uploads get parsed.
After reimplementing the above using raw
xhr resulted in the same behavior, we tried removing
FormData from the equation. Lo and behold, the
WebKitFormBoundary was gone and our images were happily slurped up by Rackspace.
TL;DR: Don’t wrap binary requests in
Fetch respects the headers you set, XHR knows better
In the same project, we also had a use case for uploading CSV files. This time we were not interfacing with Rackspace, but rather our own API backend using gocsv for CSV processing.
Nonetheless, we once again found ourselves using a combination of
Again, seemingly innocuous code was somehow failing. Our API returned 400 errors, claiming it couldn’t find a ‘form boundary’. But how does one add a form boundary? This time using
xhr instead of
fetch fixed the issue – it was adding the form boundaries for us. But why? As it turns out
xhr was blowing away our
Content-Type header and appending its own, containing the appropriate form boundary, while
fetch was respecting the
Content-Type header we set and allowing it to fail. So when using
fetch to submit
multipart forms, the way to properly set the
Content-Type header is to just leave it off.
TL;DR: Don’t set the
Content-Type header and the browser will do it for you.