How to correctly attach file to formData before POSTing to server?
Set Content-Type: undefined
When posting objects created by the FormData API it is important to set the content type header to undefined
.
const insightPDF = (formData) => {
console.log(' formData', formData)
var config = { headers: {'Content-Type': undefined} };
return $http.post('/app/api/insights_pdf', formData, config)
.then((res) => {
console.log('PDF uploaded res', res)
return res;
}).catch(apiError);
};
Normally the AngularJS framework, automatically add the content type header as application/json
which overrides the content type set by the XHR Send() method. When the XHR API sends a FormData object, it automatically sets the content type to multipart/form-data
with the proper boundary.
From the Docs:
The $http service will automatically add certain HTTP headers to all requests
To explicitly remove a header automatically added via
$httpProvider.defaults.headers
on a per request basis, Use the headers property, setting the desired header toundefined
. For example:var req = { method: 'POST', url: 'http://example.com', headers: { 'Content-Type': undefined }, data: { test: 'test' } }
— AngularJS $http Service API Reference - Setting HTTP Headers
FormData objects like blobs are host-defined objects non-native to JavaScript. Not all of their properties can be seen by console.log
or console.dir
. Files are a special type of blob. The data is not necessarily loaded from disk. Usually, the data is streamed from disk only when needed by a specific API.
Avoid Extra Overhead -- Send files directly
Content in multipart/form-data
uses base64 encoding which adds 33% extra overhead. If uploading only one file, it is more efficient to send the file blob directly.
//MORE Efficient; Avoids base64 encoding overhead
const insightPDF = (dataObject) => {
var config = { headers: {'Content-Type': undefined} };
return $http.post('/app/api/insights_pdf', dataObject, config)
.then((res) => {
console.log('PDF uploaded res', res)
return res;
}).catch(apiError);
};
var file = inputElem[0].files[0];
insightPDF(file);
If the server can accept binary content directly, it is best to send files that way. The XHR API will automatically set the content type to that of the file.
Related videos on Youtube
Leon Gaban
Investor, Powerlifter, Crypto investor and global citizen You can also find me here: @leongaban | github | panga.ventures
Updated on May 25, 2022Comments
-
Leon Gaban almost 2 years
I've been following this FormData tutorial here, however have yet to understand how the formData object works.
My input form
<input type="file" id="file-id" class="w300px rounded4px" name="file" placeholder="PDF file"> <button class="btn-upload-pdf" ng-click="asub.uploadPDF()">Upload</button>
Here is the upload button function:
this.uploadPDF = () => { const formData = new FormData(); const fileInput = document.getElementById('file-id'); const file = fileInput.files[0]; formData.append('pdf-file', file); console.log('formData', formData) return ApiFactory.insightPDF(formData).then((res) => { console.log('res', res); return res; }); };
When I log out the
fileInput
object.files[0]
I see the file I just attached:It would seem to mean that this object should be enough to send along to the POST. However this is the next step:
formData.append('pdf-file', file);
I log out
formData
before I send it into my Factory and this is the result, I don't see the keypdf-file
or that PDF anywhere, just a bunch of methods? Where does the file get appended too? How does formData contain the actual PDF?I need to attach something from the formData object I presume:
The Factory that makes the POST request
const insightPDF = (formData) => { console.log(' formData', formData) return $http.post('/app/api/insights_pdf', formData).then((res) => { console.log('PDF uploaded res', res) return res; }).catch(apiError); };
-
jbrown over 7 yearsYou should be posting fromData not file.
-
Leon Gaban over 7 yearsAh sorry, I am posting fromData, I just changed the var name to file when inside of the
insightPDF
function, I should probably change that back.
-
-
Leon Gaban over 7 yearsThanks! No more errors... now just need to finish the backend endpoint :) is there a way tho to see where the file is attached inside of the FormData object? When I log it out, it's still just a bunch of methods. What does the
formData.append('pdf-file', file);
do? -
georgeawg over 7 yearsAs I said in my answer, the
formData
object is host-environment object. It is an exotic non-native proxy for things in the host environment. JavaScript can only see the methods and properties made available to the language. Under the hood there is more. Web APIs likeFileReader
andXHR send
have connections under the hood to host environment methods and properties. -
georgeawg about 5 yearsTo see what is attached inside the FormData object, use the formData.entries() method. For an example, see form data is not appending file object.