I'm in the process of creating a small next.js application which includes a file upload form. The upload almost works. Uploading simple text files works just fine, but binary files like pictures changes slightly and I can't figure out why.
The content of the file is read using the javascript FileReader and the output of that is used as body for the post request.
The byteLength on the client size matches the byte size of the file with ls -l so I'm assuming that value is correct.
But when the size of the body on the api side is logged it is a few bytes less for binary files. For text the sizes are the same.
In the real code the file content is then send to another api which stores the content in a database and makes it available for download. The content is not the same - it looks like the "pattern" of where the bytes are for pictures have remained, but the bytes are different.
For example, a small png file with size of 1764 bytes is still 1764 bytes on the client side but becomes 1731 bytes on server side.
Here is the client side code:
import { useState } from "react";
const TestPage = () => {
const [file, setFile] = useState();
function readFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = (res) => {
resolve(res.target.result);
};
reader.onerror = (err) => reject(err);
reader.readAsArrayBuffer(file);
});
}
function onFilesChosen({ target }) {
setFile(target.files[0]);
}
async function onClick(event) {
event.preventDefault();
const fileContent = await readFile(file);
console.log(fileContent.byteLength);
fetch("/api/upload", {
method: "POST",
body: fileContent,
headers: {
"Content-Type": "application/octet-stream",
},
}).then((r) => alert("Uploaded!"));
}
return (
<div>
<form>
<div className="form-group">
<label htmlFor="file-upload">Choose file</label>
<input className="form-control-file" onChange={onFilesChosen} type="file" name="file-upload"/>
</div>
<button type="submit" onClick={onClick}>Upload</button>
</form>
</div>
);
};
export default TestPage;
And this is the simple server side code (just to show the received file size):
export default function handler(req, res) {
const data = req.body;
console.log("length", data.length);
return res.status(200).end();
}
I've tried using axios but couldn't get it to work.
Any suggestions about what I do wrong?