I'm trying to send an image through axios POST request. The request is going through, but the image is not uploading.
Here is my code,
const screenshotPath = path.join(os.tmpdir(), 'screenshot.png');
var bodyFormData = new FormData();
//bodyFormData.append('uploadedFile', screenshotPath);
bodyFormData.append('uploadedFile', fs.createReadStream(screenshotPath));
axios({
method: 'post',
url: url,
data: bodyFormData,
config: {
headers: {
'Content-Type': 'multipart/form-data',
Authorization: 'Bearer ' + token
}
}
})
Is it because of the filename path ?
this is my screenshotPath
C:\Users\oem\AppData\Local\Temp\screenshot.png
You are using createReadStream function from the File System library of Node. But Node is running on server-side and here you are working with a react application which is running on client side.
Please check MDN documentation on how to upload files from front-end applications.
Related
recently I got an issue with uploading documents functionality in Expo CLI - React native, the issue is the file is not delivering to the backend like FormData() it arrives in a weird array, not like the website at all, I got the same endpoint connected to React JS project and it works fine and the browser delivers the documents correctly,
But not sure what is wrong with FromData here,
I also tried react-native-fs but it's not compatible with Expo
and here is my code
let formData = new FormData();
formData.append('file', doc);
let token = this.props.user.token;
let header = { headers: { 'Accept': '*', 'Authorization': 'Bearer '+token, 'Content-Type': 'multipart/form-data' } };
let res = await axios.post(BackendURL+'/porta/files/upload/'+document.projectDocumentId, formData, header);
if(res.data.success === true){
alert('File uploaded successfully');
this.props.ReloadData(true);
}
console.log(doc);
Issue has been solved,
the problem where in the header, i removed the content type & accept like this
let formData = new FormData();
formData.append('file', {
name: doc.name,
uri: doc.uri,
type: "application/pdf"
});
this.props.loadingStatus(true);
let token = this.props.user.token;
let header = { headers: { 'Authorization': 'Bearer '+token } };
let res = await axios.post(BackendURL+'/portal/files/upload/'+document.projectDocumentId, formData, header);
I am working on React web app with a Flask backend. how can I send a file with JSON data on the body?
I try the code below but is not working
const file = e.target.file[0]
const user = [{name: 'Ma'}]
const formData = new FormData()
dormData.append('file', file)
dormData.append('user', user)
const post = await axios({
method: 'post',
url: 'http://127.0.0.1:5000/route',
data: formData,
headers: { "Content-Type": "multipart/form-data" }
})
You have to set the Content-Type header as application/json and you can set the body as your json
Your code would look something like this
const post = await axios({
method: 'post',
url: 'http://127.0.0.1:5000/route',
headers: { "Content-Type": "application/json" },
body: JSON.stringify(myJson) //insert your stringified json here
})
Since you are creting a react web app, it's easy to structure a JSON from a form.
You are spelling formData wrong. Use this code:
formData.append('file', file)
formData.append('user', user)
On Node Server i have this code . Its basically sending the browser POST data to api server and recieves a file as chunk data and the same data is send back to browser via pipe response . But the issue is the api reponse is correct and i can write the file using nodejs locally but it doesnt push download file in browser
router.post('/MyURLOnNODE', function (req, res) {
var MyJsonData = { some Data };
res.writeHead(200, {'Content-disposition': 'attachment; filename=fileArchive.tgz','Content-Type': 'application/force-download'});
try {
request({
url: 'SomeAPI Url', //URL to hit
method: 'POST',
json: MyJsonData
}).pipe(res);
} catch(e) {
console.log("Pipe error",e);
}
console.log("File Streaming Called ",MyJsonData)
}
);
Client Side Code ...This was an attempt to create a blob and use it on urlObject. but the downloaded file is corrupted when i checked in hex.
$http({
method: 'POST',
url: 'MyURLOnNODE',
data: PostData, //forms user object
headers: {
'Content-Type': 'application/json'
}
})
.then(function (data) {
var response=data.data;
var id = Flash.create('success', "Folder Archieved", 5000);
var a = document.getElementById('arch');
a.href = URL.createObjectURL(new Blob([response]));
a.download = "FolderMe.tgz";
a.type='application/octet-stream '
a.click();
}
So is there any solution to this ? either on NodeJs Side or On browser
Update : https://stackoverflow.com/a/7969061/7078299
This thread says its hard to convert an ajax request to download file. So i need to work on client on using urlobject. But blob isnt working with stream data. How to solve it
You can use a node module called file-saver and use saveAs method provided by it and download the file on the client side.
First npm install file-saver;
You can use it as
import {saveAs} from 'file-saver';
and inside your then block you need to add this line
saveAs(new Blob([response]), <your file name>)
It will auto-download your file.
i fixed the issue by adding a reponseType on Client Side Code. Now the blob and ObjectUrl works correctly
$http({
method: 'POST',
url: 'MyUrl',
data: PostData, //forms user object
headers: {
'Content-Type': 'application/json'
},
responseType: 'arraybuffer'
})
.then(function (response) {
console.log(response);
var headers = response.headers();
var blob = new Blob([response.data],{type:headers['content-type']});
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "Archive.tgz";
link.click();
});
I am trying to upload a file from a react front end to a C# backend. I am using drop zone to get the file and then I call an api helper to post the file but I am getting different errors when I try different things. I am unsure exactly what the headers should be and exactly what I should send but I get two distinct errors. If I do not set the content-type I get 415 (Unsupported Media Type) error. If I do specify content type as multipart/form-data I get a 500 internal server error. I get the same error when the content-type is application/json. The url is being past in and I am certain it is correct. I am unsure if the file should be appended as file[0][0] as I have done or as file[0] as it is an array but I believe it should be the first. Any suggestions welcome :) Here is my api post helper code:
export const uploadAdminFile = (file, path, method = 'POST', resource =
config.defaultResource) => {
const url = createUrl(resource, path);
const data = new FormData();
data.append('file', file[0][0]);
data.append('filename', file[0][0].name);
const request = accessToken =>
fetch(
url,
{
method,
mode: 'cors',
withCredentials: true,
processData: false,
headers: {
Accept: 'application/json',
'Content-Type': 'application/json', //'multipart/form-data',
Authorization: `Bearer ${accessToken}`,
},
body: data,
})
.then(res => res.json())
.then(success => console.log('API HELPER: file upload success: ', success)
.catch(err => console.log('API HELPER: error during file upload: ', err)));
return sendRequest(request, resource);
};
Thanks for the help and suggestions, it turned out to be a backend issue but even still I learned a lot in the process. I will post my working code here in case anyone comes across this and finds it useful.
export const uploadAdminFile = (file, path, resource=config.defaultResource) => {
const url = createUrl(resource, path);
const formData = new FormData();
formData.append('file', file[0][0]);
formData.append('filename', file[0][0].name);
const request = accessToken =>
fetch(url,
{
method: 'POST',
headers: {
Accept: 'application/json',
Authorization: `Bearer ${accessToken}`,
},
body: formData,
});
return sendRequest(request, resource);
};
As mentioned, the file name does not need to be sent separately and count be omitted. I am indexing the file this way because I get it from dropzone as an array and I only want a single file (the first one in the array). I hope this helps someone else out and here is a link to the mdn fetch docs (good information) and a good article on using fetch and formData.
I am trying to upload files to Google Drive in Angular 2. So far I am able to upload files, but without title and they are "Untitled"
Here is code to do that:
gDriveUploader(file): Promise<any> {
let authToken = tokenHere;
const url = `https://www.googleapis.com/upload/drive/v2/files/`
let formData:FormData = new FormData();
formData.append('title', file, file.name);
let headers = new Headers({
'Authorization': 'Bearer ' + authToken
});
headers.append('Accept', file.type);
let options = new RequestOptions ({
headers: headers,
});
console.log('OPTIONS: ', options)
return this.http.post(`${url}`, formData, options)
.toPromise()
.then(response => response.json())
.catch(e=>console.log(e));
}
I know, that in order to send metadata with file, I have to add this metadata to Request body and use at multipart or resumable upload types. But here I faced issue after issue and just can't make it properly.
I completely messed up. Here is on of my approaches with resumable upload type:
gDriveUploader(file): Promise<any> {
let authToken = token;
const url = `https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable`
console.log('FILE TO UPLOAD: ', file)
let formData:FormData = new FormData();
formData.append('name', file, file.name);
let headers = new Headers({
'Authorization': 'Bearer ' + authToken,
'Content-Type': 'application/json; charset=UTF-8', //if remove "Bad Content" Error
//'Content-Length': file.size, not sure if this one right?
});
let options = new RequestOptions ({
headers: headers,
});
return this.http.post(`${url}`, formData, options)
.toPromise()
.then(response => response.json())
.catch(e=>console.log(e));
}
that's not only two of my approaches...
According to Drive API for resumable upload:
POST https://www.googleapis.com/drive/v3/files?uploadType=resumable
HTTP/1.1
Authorization: Bearer [YOUR_AUTH_TOKEN]
Content-Length: 38
Content-Type: application/json; charset=UTF-8
X-Upload-Content-Type: image/jpeg
X-Upload-Content-Length: 2000000
What is Content-Length: 38? it's file length and I can just use file.size?
With multipart I can't figure out how to add those boundary separator in the request.
I saw some Q and A, that multipart were not supported by Angular, but that was 1-2 year ago. What about now?
Can I somehow use resumable upload to GDrive with additional file metadata using standard Angular features?
So. A bit more research on how API works. I came up with the following solution for resumable file upload. Main Idea, that first time I have to make a request and "set metadata" for my file and get response with the link, where to upload the file. And this link came as one of the response header called location.
Here is fully working code. Just pass File object to the first function.
I just quickly made 2 functions for this. First one will set metadata (just name) and call second function to upload just binary data.
gDriveUploader(file): Promise<any> {
let authToken = token
const url = `https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable`
let headers = new Headers({
'Authorization': 'Bearer ' + authToken,
'Content-Type': 'application/json; charset=UTF-8',
});
let options = new RequestOptions ({
headers: headers,
});
return this.http.post(`${url}`, {name: file.fullName}, options) //just set the name
.toPromise()
.then(response => this.gDriveUploadFile(file, response.headers.get('location'))) //call second function to upload `file` to proper URI from response
.then(response => {
let id = response.json().id //parse id of uploaded file
let resp = {fileName: file.fullName, fileType: file.fileType, fileSize: file.size, fileId: id} //create an object with file file properties, if you need that
return resp // return object back to function that called this service
})
.catch(e=>console.log(e));
}
Second function to upload data:
gDriveUploadFile(file, url): Promise<any> { //file and url we got from first func
let authToken = token
let headers = new Headers({
'Authorization': 'Bearer ' + authToken,
'Content-Type': 'application/json; charset=UTF-8',
'X-Upload-Content-Type': file.type
});
let options = new RequestOptions ({
headers: headers,
});
return this.http.post(`${url}`, file, options) //call proper resumable upload endpoint and pass just file as body
.toPromise()
}
Maybe solution not ideal, so far I do not handle errors here and do not use resumable features like uploading by chunks, just upload file at once. But hopefully if someone else stuck with GDrive uploading can get an idea.