vespaiach / axios-fetch-adapter

Fetch adapter for axios
https://www.npmjs.com/package/@vespaiach/axios-fetch-adapter
MIT License
100 stars 52 forks source link

Incompatible with Service Workers and `FormData` #20

Open conor-odro opened 2 years ago

conor-odro commented 2 years ago

I recently came across an issue that is somewhat related to #16 where I was trying to upload a file to an AWS S3 bucket with a Presigned POST URL from inside a Manifest V3 Chrome Extension which requires the use of Service Workers.

axios.defaults.adapter = fetchAdapter;

const formData = new FormData();
Object.entries(fields).forEach(([key, value]) => {
  formData.append(key, value);
});
formData.append('file', file);
await axios.post(s3Url, formData);

Unfortunately this was erroring due to the Content-Type header being set to application/www-x-form-urlencoded instead of multipart/form-data and the WebKit boundary injected by the browser.

Looking into the code it seems the issue is caused by the use of isStandardBrowserEnv() inside the check which should automatically remove the Content-Type header, allowing the browser to fill in the correct one. This helper method is expecting window and document to be defined which is not possible in a Service Worker environment.

if (method !== 'GET' && method !== 'HEAD') {
    options.body = config.data;

    // In these cases the browser will automatically set the correct Content-Type,
    // but only if that header hasn't been set yet. So that's why we're deleting it.
    if (isFormData(options.body) && isStandardBrowserEnv()) {
        headers.delete('Content-Type');
    }
}

@vespaiach Removing the isStandardBrowserEnv() from the if statement solves my problem and allows the file upload to succeed, but I am unsure if it will have any knock on effect to other use cases of this package?

rkovalov commented 2 years ago

faced with the same issue

jimmywarting commented 1 year ago

It's way better to check if it's a spec compliant FormData

You could use options?.body?.[Symbol.toStringTag] === 'FormData' to check if it should or shouldn't delete the header. instead of using if (isFormData(options.body) && isStandardBrowserEnv())