I need to include the image as binary data in my uploading request using multipart form data, and it seems not working, any advise will be appreciated.
my code:
const [selectedFile, setSelectedFile] = useState(null);
const handleSubmit = async (event) => {
event.preventDefault();
const formData = new FormData();
formData.append('selectedFile', new Blob([selectedFile], { type: 'application/octet-stream' }));
const data = {
uploadLink,
formData,
};
const headers = {
'Content-Type': 'application/octet-stream' ,
Accept: 'application/vnd.vimeo.*+json;version=3.4',
};
try {
await axios
.post(`${backendPostPath}/thumbnail-upload`, data, {
headers,
})
.then((response) => {
applyThumbnial();
console.log(response);
});
} catch (error) {
console.log(error);
}
};
const handleFileSelect = (event) => {
setSelectedFile(event.target.files[0]);
};
include formData as axios data parameter instead of your data object, so you can also include uploadLink in the formData:
const formData = new FormData();
formData.append('selectedFile', new Blob([selectedFile], { type: 'application/octet-stream' }));
formData.append('uploadLink', uploadLink)
//...
await axios
.post(`${backendPostPath}/thumbnail-upload`, formData, {
headers,
})
Related
TDLR: Using s3 presigned post url to upload file to s3. Works fine on the browser but fails on the server.
I have a simple lambda function that generates presigned post url that can be consumed either in the browser or in the server.
During testing I noticed that the upload works fine one the browser but fails if I try to upload a file from a server even tho the code is identical.
The error i get is:
You must provide the Content-Length HTTP header
Detailed error:
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>MissingContentLength</Code>
<Message>You must provide the Content-Length HTTP header.</Message>
<RequestId>JP75YMFARK0G3X5Z</RequestId>
<HostId>toHsKmxmVYYAtac94cQoy8wXoregKG3PNBm97c3gQewEmKxLggcumTAP882T/pJNWx/lxRgH98A=</HostId>
</Error>
Request failed with status code 411
I checked online and found many threads about this issue but unfortunately not a single suggestion helped me.
Code I am running in the server
const axios = require('axios');
const { createReadStream, readFileSync } = require('fs');
const FormData = require('form-data');
const getPostPresignedUrl = async () => {
var config = {
method: 'post',
url: LAMBDA_GET_URL,
headers: {
'Content-Type': 'application/json',
},
data: JSON.stringify({
key: 'test-2.jpg',
fileType: 'image/jpeg',
}),
};
const {
data: { data },
} = await axios(config);
return data;
};
const uploadFileToS3 = async (fields, url) => {
const formData = new FormData();
Object.entries(fields).map(([key, value]) => {
formData.append(key, value);
});
const file = createReadStream('./test-1.jpg');
formData.append('file', file);
try {
const { data } = await axios({
url,
method: 'post',
headers: {
'Content-Type': 'multipart/form-data',
},
data: formData,
});
} catch (error) {
if (error instanceof axios.AxiosError) {
console.log(error.response.data);
}
console.log(error.message);
}
};
const init = async () => {
const { fields, url } = await getPostPresignedUrl();
await uploadFileToS3(fields, url);
};
init();
Code I am running in the browser:
const form = document.getElementById('form');
const input = document.getElementById('file');
const getPostPresignedUrl = async (name) => {
var config = {
method: 'post',
url: LAMBDA_GET_URL,
headers: {
'Content-Type': 'application/json',
},
data: JSON.stringify({
key: name,
fileType: 'image/jpeg',
}),
};
const {
data: { data },
} = await axios(config);
return data;
};
const uploadFileToS3 = async (fields, url, file) => {
const formData = new FormData();
Object.entries(fields).map(([key, value]) => {
formData.append(key, value);
});
formData.append('file', file);
try {
const { data } = await axios({
url,
method: 'post',
headers: {
'Content-Type': 'multipart/form-data',
},
data: formData,
});
} catch (error) {
if (error instanceof axios.AxiosError) {
console.log(error.response.data);
}
console.log(error.message);
}
};
const handleSubmit = async (e) => {
e.preventDefault();
const file = input.files[0];
const data = await getPostPresignedUrl(file.name);
await uploadFileToS3(data.fields, data.url, file);
};
form.onsubmit = handleSubmit;
Using raw HTML when I post a file to a flask server using the following I can access files from the flask request global:
<form id="uploadForm" action='upload_file' role="form" method="post" enctype=multipart/form-data>
<input type="file" id="file" name="file">
<input type=submit value=Upload>
</form>
In flask:
def post(self):
if 'file' in request.files:
....
When I try to do the same with Axios the flask request global is empty:
<form id="uploadForm" enctype="multipart/form-data" v-on:change="uploadFile">
<input type="file" id="file" name="file">
</form>
uploadFile: function (event) {
const file = event.target.files[0]
axios.post('upload_file', file, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
}
If I use the same uploadFile function above but remove the headers json from the axios.post method I get in the form key of my flask request object a csv list of string values (file is a .csv).
How can I get a file object sent via axios?
Add the file to a formData object, and set the Content-Type header to multipart/form-data.
var formData = new FormData();
var imagefile = document.querySelector('#file');
formData.append("image", imagefile.files[0]);
axios.post('upload_file', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
Sample application using Vue. Requires a backend server running on localhost to process the request:
var app = new Vue({
el: "#app",
data: {
file: ''
},
methods: {
submitFile() {
let formData = new FormData();
formData.append('file', this.file);
console.log('>> formData >> ', formData);
// You should have a server side REST API
axios.post('http://localhost:8080/restapi/fileupload',
formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(function () {
console.log('SUCCESS!!');
})
.catch(function () {
console.log('FAILURE!!');
});
},
handleFileUpload() {
this.file = this.$refs.file.files[0];
console.log('>>>> 1st element in files array >>>> ', this.file);
}
}
});
https://codepen.io/pmarimuthu/pen/MqqaOE
If you don't want to use a FormData object (e.g. your API takes specific content-type signatures and multipart/formdata isn't one of them) then you can do this instead:
uploadFile: function (event) {
const file = event.target.files[0]
axios.post('upload_file', file, {
headers: {
'Content-Type': file.type
}
})
}
Sharing my experience with React & HTML input
Define input field
<input type="file" onChange={onChange} accept ="image/*"/>
Define onChange listener
const onChange = (e) => {
let url = "https://<server-url>/api/upload";
let file = e.target.files[0];
uploadFile(url, file);
};
const uploadFile = (url, file) => {
let formData = new FormData();
formData.append("file", file);
axios.post(url, formData, {
headers: {
"Content-Type": "multipart/form-data",
},
}).then((response) => {
fnSuccess(response);
}).catch((error) => {
fnFail(error);
});
};
const fnSuccess = (response) => {
//Add success handling
};
const fnFail = (error) => {
//Add failed handling
};
This works for me, I hope helps to someone.
var frm = $('#frm');
let formData = new FormData(frm[0]);
axios.post('your-url', formData)
.then(res => {
console.log({res});
}).catch(err => {
console.error({err});
});
this is my way:
var formData = new FormData(formElement);
// formData.append("image", imgFile.files[0]);
const res = await axios.post(
"link-handle",
formData,
{
headers: {
"Content-Type": "multipart/form-data",
},
}
);
How to post file using an object in memory (like a JSON object):
import axios from 'axios';
import * as FormData from 'form-data'
async function sendData(jsonData){
// const payload = JSON.stringify({ hello: 'world'});
const payload = JSON.stringify(jsonData);
const bufferObject = Buffer.from(payload, 'utf-8');
const file = new FormData();
file.append('upload_file', bufferObject, "b.json");
const response = await axios.post(
lovelyURL,
file,
headers: file.getHeaders()
).toPromise();
console.log(response?.data);
}
There is an issue with Axios version 0.25.0 > to 0.27.2 where FormData object in a PUT request is not handled correctly if you have appended more than one field but is fine with one field containing a file, POST works fine.
Also Axios 0.25.0+ automatically sets the correct headers so there is no need to specify Content-Type.
For me the error was the actual parameter name in my controller... Took me a while to figure out, perhaps it will help someone. Im using Next.js / .Net 6
Client:
export const test = async (event: any) => {
const token = useAuthStore.getState().token;
console.log(event + 'the event')
if (token) {
const formData = new FormData();
formData.append("img", event);
const res = await axios.post(baseUrl + '/products/uploadproductimage', formData, {
headers: {
'Authorization': `bearer ${token}`
}
})
return res
}
return null
}
Server:
[HttpPost("uploadproductimage")]
public async Task<ActionResult> UploadProductImage([FromForm] IFormFile image)
{
return Ok();
}
Error here because server is expecting param "image" and not "img:
formData.append("img", event);
public async Task<ActionResult> UploadProductImage([FromForm] IFormFile image)
i have a redux-from submission, console log look like this
{
id: "x",
parentId: "b",
editing: true,
logo: FileList,
}
Logo FileList contains my uploaded file name and file, i think
0: File(19355) {name: "11964821.jpeg", lastModified: ......
using fetch to send to nodejs, image contain my files and above data
function Update(image) {
const requestOptions = {
method: 'POST',
headers: { ...authHeader(), 'Content-Type': 'application/x-www-form-urlencoded' },
body: JSON.stringify(image)
};
return fetch(`${apiUrl}/API`, requestOptions).then(handleResponse)
.then( data => { return data; });
}
but this data not receiving nodejs, because is tried re.file etc.. its shows undefined
app.post('/image', upload.single('logo'), function (req, res, next) {
})
include formdata
const onSubmit = (image, dispatch)=>{
var formData = new FormData();
formData.append('logo',image.logo[0]);
var imageNew = {...image,formData};
dispatch(imageActions.companyProfileLogoUpdate(imageNew)) ;
}
now log is
formData: FormData {}
id: "5c66478b0814720a4365fe72"
logo: FileList {0: File(19355), length: 1}
parentId: "5c66478b0814720a4365fe71"
let formData = new FormData();
formData.append('logo' , {{your image file}}
// upload file as
let result = await sendServerRequestForForm(url,formData);
function sendServerRequestForForm(url,data) {
var promise = new Promise(function(resolve) {
resolve($.ajax({
url,
method : 'POST',
data,
processData: false,
contentType: false,
success: function(data) {
return data
},
error: function (err) {
try{
let responseStatus = err.responseJSON
// watch your response
}catch (e) {
console.log('Field to get response');
}
}
}));
});
return promise
}
for fetch API you can try this
let formData = new FormData();
formData.append('logo', fileList[0]);
fetch(url, {
method: 'post',
body: data,
})
.then(…);
move formData to fetch file and remove header content type, Try this
function Update(image) {
var formData = new FormData();
formData.append('logo',image.logo[0]);
const requestOptions = {
method: 'POST',
headers: { ...authHeader() },
body: formData
};
return fetch(`${apiUrl}/API`, requestOptions).then(handleResponse)
.then( data => { return data; });
}
First thing is for using fetch api for post content-type header should match typeof body. since your body is json stringified your contentType header should be 'application/json' . more about this .
Second. since you want to upload an image which a file you should use FormData without requirement of setting contentType: like below:
let formData = new FormData();
formData.append('logo', image.logo[0]);
const requestOptions = {
method: 'POST',
body: formData
};
fetch(`${apiUrl}/API`, requestOptions)
.then(handleResponse)...
I am trying to set up "Cloudinary" for image uploads from my React app.
My submit function keeps responding with: "Bad Gateway 502" and "SyntaxError: Unexpected end of input".
I'm assuming something is wrong with my headers, but I can't find the issue...
handleFileSelect = (e) => {
this.formValid()
this.setState({
picture: e.target.files[0] })
}
submit(){
const CLOUDINARY_URL=
"https://api.cloudinary.com/v1_1/dvz27u2gu/image/upload"
const CLOUDINARY_UPLOAD_PRESET= "jshvp3nh"
const obj = Object.assign({}, this.state);
const formData = new FormData();
formData.append("file", obj.picture);
formData.append("upload_preset", CLOUDINARY_UPLOAD_PRESET);
fetch(CLOUDINARY_URL,{
mode: 'no-cors',
method:'post',
headers: { "Content-Type": "application/x-www-form-urlencoded"},
body:formData,
})
.then((res)=>{return res.json()})
.then(data=>console.log(data))
.catch(err=>console.log(err));
}
You can try something like the following:
<div><input type="file" onChange={this.submit}/></div>
submit = (e) => {
var file = e.target.files[0];
var data = new FormData();
data.append('upload_preset', 'jshvp3nh');
data.append('file', file);
data.append('cloud_name', 'dvz27u2gu');
const config = {
method: "POST",
body: data
};
var imgurl = "https://api.cloudinary.com/v1_1/dvz27u2gu/raw/upload";
fetch(imgurl, config)
.then(responseData => {
console.log('here');
console.log(JSON.stringify(responseData, null, 4));
console.log(responseData);
})}
This is how it worked for me.
const CLOUDINARY_URL= "https://api.cloudinary.com/v1_1/dvz27u2gu/image/upload"
const CLOUDINARY_UPLOAD_PRESET= "jshvp3nh"
const obj = Object.assign({}, this.state);
const formData = new FormData();
formData.append("file", obj.picture);
formData.append("api_key", "xx")
formData.append("api_secret", "xx")
formData.append("upload_preset", CLOUDINARY_UPLOAD_PRESET);
formData.append("timestamp", (Date.now() / 1000) | 0);
fetch(CLOUDINARY_URL,{
method:'POST',
body: formData,
})
.then((res)=>{return res.json()})
.then((data)=>{
obj.img_url_cloudinary=data.secure_url;
this.sendForm(obj);
}).catch(err=>console.log(err));;
I have an API that receives uploads of APP files and images
To send from APP to the API I use fetch
const data = new FormData();
let i = 0;
export const dataPush = (fileUri, fileType, fileName) => {
data.append('file'+i, {
uri: fileUri,
type: fileType,
name: fileName
});
i++;
};
export const uploadFiles = () => {
console.log(data);
fetch('http://192.168.0.23/apiapp/public/api/annex', {
method: 'post',
body: data
}).then(res => {
console.log(res)
});
}
But I'd like to send in the same request data obtained from a form
But I did not find a way to do it, always or just send the data, or just send the files
Is it possible to send everything in the same request? And if possible, how?
You just append whatever data that you desire that isn't file data to the FormData object.
data.append("not_a_file", "This is a string");
I did so based on Quentin's response and it worked
const formData = new FormData();
const i = 0;
export const filePush = (fileUri, fileType, fileName) => {
formData.append('file'+i, {
uri: fileUri,
type: fileType,
name: fileName
});
i++;
};
export const dataPush = (name, content) => {
formData.append(name, content);
};
export const uploadFiles = () => {
fetch('http://192.168.0.23/apiapp/public/api/annex', {
method: 'post',
body: formData
}).then(res => {
console.log(res._bodyText)
}).catch(error => {
console.log(error.message)
});
}