Hello I'm sending/POST a File from a HTML Form on a browser client to a Remix application server.
The Remix applicaton server is sending/handling my File as a async AsyncIterable.
I now need to convert it back to a File object so I can send it to a backend server as FormData.
I tried both with and without buffer for demo:
Does anyone have experiance with convert AsyncIterable to Blob then to File??
const myHandler: UploadHandler = async ({ name, contentType, data, filename }) => {
//'data' is data of type AsyncIterable<Uint8Array>
//'contentType' is 'image/png'
let dataArray1 = []; //test1 without buffer
let dataArray2 = []; //test2 with buffer
for await (const x of data) {
dataArray1.push(x); //without buffer
dataArray2.push(x.buffer); //with buffer
}
const blob1 = new Blob(dataArray1, {type: contentType});
const blob2 = new Blob(dataArray2, {type: contentType});
const file1 = new File([blob1], filename, { type: contentType });
const file2 = new File([blob2], filename, { type: contentType });
console.log('file1.size: ', file1.size);
//file1 size is 1336843 (and for file2)
//but i'm getting content-length 1337028 from my browser Form
//so I'm not sure if it's correct
return file1;
};
[![content-length size][1]][1]
[![enter image description here][2]][2]
[![enter image description here][3]][3]
[![enter image description here][4]][4]
Try passing the blob parts directly into the file constructor.
const myHandler: UploadHandler = async ({ name, contentType, data, filename }) =>
{
const dataArray1 = [];
for await (const x of data)
{
dataArray1.push(x);
}
const file1 = new File(dataArray1, filename, { type: contentType });
return file1;
};
Related
I have an input that the user can upload an image, I want to get this image and pass it to the server side and the server will store this image on a local folder, for example:
I use linux for the server so the server.js is running from the folder /home/user/project/server/server.js. When the server get the image I want it to store on the folder /home/user/project/images/img.jpg
This my code:
HTML:
<input type="file" id="imageFile" accept=".jpg, .jpeg, .png" />
Front-End:
const signup = async () => {
const name = document.getElementById("signup_name").value;
const passwd = document.getElementById("signup_passwd").value;
const image = document.getElementById("imageFile").files[0];
let formData = new FormData();
formData.append("fileToUpload", image);
const response = await fetch("http:/localhost:3000/signup", {
method: "post",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
nome: cadastro_nome,
senha: cadastro_senha,
imagem: formData
}),
});
const result = await response.json();
document.getElementById("cadastro_nome").value = "";
document.getElementById("cadastro_senha").value = "";
alert(result);
};
Back-End:
app.post("/signup", async (req, res) => {
const { name, passwd, image } = req.body;
if (!name || !passwd) {
return res.status(400).json("Dados incorretos!");
}
knex
.transaction((trx) => {
trx
.insert({
login: name,
senha: passwd,
divida: 0,
})
.into("usuarios")
.then(trx.commit)
.catch(trx.rollback)
.then(res.json("Cadastrado com sucesso!"));
})
.catch((err) => {
console.log(err);
return res.json("Login existente, tente novamente!");
});
//PUT SOMETHING HERE TO SAVE IMAGE LOCALLY, MAYBE??
});
Yes, you can first store the uploaded image as a Base64 string using the FileReader, data urls are already base64 so when you call reader.readAsDataURL the e.target.result sent to the reader.onload handler and it will be all you need, but also may need add in your HDD or do it asynchronous using res.json, check the WDN official documentation about FileReader.
(Get user's uploaded image for example)
const imgPath = document.querySelector('input[type=file]').files[0];
const reader = new FileReader();
reader.addEventListener("load", function () {
// Convert file to base64 string and save to localStorage
localStorage.setItem("image", reader.result);
}, false);
if (imgPath) {
reader.readAsDataURL(imgPath);
}
And to read the image back from the localStorage, just use querySelector or getElementById:
const img = document.getElementById('image');
img.src = localStorage.getItem('image');
About the "fd" argument must be of type number, in my case, sometimes I was using:
fs.readSync() when I should have been using fs.readFileSync()
fs.writeSync() usage but should be fs.writeFileSync()
fr.write() could be in your case fs.writeFile()
The comment of #Dimava in your question can work too, I flagged up.
For more help, consult this post related to your similar question! ;)
How do I download the document I receive in return in react?
Here is the my node.js app. fetchContracts is a function which getting data from mongodb then ganere a excel file by using json2xls npm package.
Its returns as like this:
const xls = json2xls(contracts);
return xls;
If tying to write file fs.writeFileSync(path.join(__dirname, filename), xls, 'binary'); generating successfully xlsx file in the server.
But I need to send the file to the server without writing file. For this, I made some experiments that you can see below.
export const EXPORT_EXCEL: SessionedAsyncControllerType = async (req: SessionedRequest, res: Response) => {
const fileName = 'hello_world.xlsx'
const fileType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
const xls = await fetchContracts({}, "fileName.xlsx")
const fileData = xls;
res.writeHead(200, {
'Content-Disposition': `attachment; filename="${fileName}"`,
'Content-Type': fileType,
})
const download = Buffer.from(fileData, 'base64')
res.end(download)
}
I getting response like this.
But i don't know how can i download the response file in react?
In react side:
return api.get(`api/excel`).then((response: any) => {
console.log(response);
})
I just log into console. How can i download directly file which coming node response in react.js?
Try this
return api.get(`api/excel`).then((response: any) => {
const outputFilename = `${Date.now()}.xlsx`;
// If you want to download file automatically using link attribute.
const url = URL.createObjectURL(new Blob([response.data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', outputFilename);
link.click();
})
I have an image file in the server side, and would like to send this image to the client side to display it in the web. It seems like URL.createObjectURL can only be used in a DOM, it sounds impossible to convert the image file to URL in expressJS, or is there any other way to return the image as URL from server side?
I am now trying to send the image buffer and try to use URL.createObjectURL on the client side. It seems like res containing a bunch of weird character string, and I tried to create a Blob, but the image does not render on the web at all.
fetch(`http://localhost:9000/foo`)
.then((res) => res.text())
.then((res) => {
var test = new Blob([res], { type: "image/jpeg" });
props.setImageSrc((prev) => [
...prev,
URL.createObjectURL(test),
]);
});
router.get("/", function (req, res, next) {
var buffer = fs.readFileSync("/Users/foo/bar/image1.jpeg");
var bufferBase64 = new Buffer.from(buffer);
res.send(bufferBase64);
});
Below are part of the res I got on the client side
%&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz�������������������
Use this function to convert the base64 buffer string to blob
const b64toblob = (string, fileType) => {
const byteCharacters = atob(string);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
return new Blob([byteArray], { type: `image/${fileType}` });
};
Receive base64 buffer string from server
fetch(`http://localhost:9000/foo`)
.then((res) => res.text())
.then((res) => {
const blob = b64toblob(buffer, "jpeg");
props.setImageSrc((prev) => [
...prev,
URL.createObjectURL(blob),
]);
});
In server, read the file and convert to base64 buffer
router.get("/", function (req, res, next) {
var buffer = fs.readFileSync("/Users/foo/bar/image1.jpeg");
var bufferBase64 = new Buffer.from(buffer);
res.send(bufferBase64.toString("base64"));
});
I am trying to set the types for a file upload, but I can not believe I have to define every single property on the file object
export type FileProps = {
path: string
lastModified: number
slice: () => void
stream: () => void
text: () => void
arrayBuffer: ArrayBuffer
name: string
size: number
type: string
}
const [files, setFiles] = useState<FileProps[]>([])
I upload a few files and store them on the state, but then when I try to add to the form
const formData = new FormData()
for (const file of files) {
formData.append('files', file)
}
I get an error on file
If you just use File, then you get exactly what you want:
const [files, setFiles] = useState<File[]>([])
const formData = new FormData()
for (const file of files) {
formData.append('files', file)
}
That should get you all the fields documented here: https://developer.mozilla.org/en-US/docs/Web/API/File
See playground
The second argument of the FormData.append method is Blob or USVString.
You had mentioned in a comment that the entire structure needs to be sent to the backend. So, you need to convert the FormData instance to a blob.
for (const file of files) {
formData.append('files', new Blob([JSON.stringify(file)], {type : 'text/html'});)
}
I have the following request to send image files to my PHP endpoint:
const formData = new FormData();
Object.keys(this.state.productData).forEach((key) => {
if (key === "files") {
formData.append(key, this.state.productData[key]);
}
});
for (let value of formData.values()) {
console.log(value);
}
fetch(`${process.env.REACT_APP_API_URL}/products/submit`, {
method: 'POST',
body: formData,
})
Now as proof the value i get from the console.log is this:
[object File]
In my PHP endpoint I do the following:
return response([$request->get('files')]);
This however results in:
["[object File]"]
Also
response([$request->hasFile('files'), $request->get('files')]);
returns: [true, null]
Any help to get my image files from my react app to php endpoint would be highly appreciated.
My Image files are stored into the stated as the "files" values after i upload them using: FileReader() in js:
handleImageChange = e =>{
e.preventDefault();
let files = Array.from(e.target.files);
files.forEach((file, i) => {
let reader = new FileReader();
reader.onloadend = () => {
this.setState(prevState => ({
files: [...prevState.files, file],
imagesPreviewUrls: [...prevState.imagesPreviewUrls, reader.result]
}));
};
reader.readAsDataURL(file);
});
};
To retrieve image files from FormData values in your Lumen PHP application, you need to do the following:
return response([$request->file('files')]);