I am trying to include the option to upload an image in my app (React in the front side and NodeJS in the server one). The issue I am facing is that I am not able to send the file to the server. I saw other questions in this site and tutorials in other websites but I can't find what I'm doing wrong, so I hope you can, please, help me out.
This is part of my React code:
export default class DisplayPicture extends React.Component {
constructor(props) {
super(props);
// etc
}
onImageChange = (event) => {
if (event.target.files && event.target.files[0]) {
const img = event.target.files[0];
const formData = new FormData();
formData.append("image", img);
this.service
.uploadPicture(formData) // API call through a service
.then((backAnswer) => console.log(backAnswer))
.catch((err) => console.log(err));
}
};
render() {
return (
<div>
<p>Please, upload an image</p>
<input type="file" name="image" onChange={this.onImageChange} />
</div>
);
}
}
However, when I take a look at what the service sends to the server, it is an empty object and the server gets obviously the same in req.body and an "undefined" when looking for req.file.
I know the usual thing is to upload files by using a form, but I've already tried and got the same result, so I shared the shorter version.
Thanks in advance!!
Related
I'm trying to upload multiple images in React (nextjs) from <input onChange={onChange} type='file' name='file' multiple/>
But which way is more proper to do it? Some hours of googling didn't helped me
This is my approach(that ofc doesn't work, otherwise i would not have to write it):
I stored images' srcs using useState hook:
const [imgsSrc, setImgsSrc] = useState([])
And this is my "input on change handler":
const onChange = (changeEvent: any) => {
for (let file of changeEvent.target.files) {
setTimeout(() => {
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => { setImgsSrc([...imgsSrc, reader.result]) }
reader.onerror = () => { console.log(reader.error)}
}, 1000)
}
}
My input one more time
<input onChange={onChange} type='file' name='file' multiple/>
And my way to trying to show images to user
{ imgsSrc.map((link) => { <img src={link}/> }) }
But it doesn't show me anything, so i have couple of questions that my nerve cells would be happy to get an answer to
why it doesn't work
does "saving images to public folder in root app directory" a good approach to save images
can i store base64 encode URLs remotely and get it every request, decode it and get an image
please...
You basically have a couple of mistakes that prevent your code from showing anything:
function App() {
const [imgsSrc, setImgsSrc] = useState([]);
const onChange = (e) => {
for (const file of e.target.files) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
setImgsSrc((imgs) => [...imgs, reader.result]);
};
reader.onerror = () => {
console.log(reader.error);
};
}
};
console.log(imgsSrc, imgsSrc.length);
return (
<div>
<input onChange={onChange} type="file" name="file" multiple />
{imgsSrc.map((link) => (
<img src={link} />
))}
</div>
);
}
Since the file reader is asynchronous, you need to tell React to update the state using the most recent state, or you will have bugs, because setState is asynchronous as well, and the loop commands get batched and override the one another.
The fact that you did not have any image output is due to the fact that you are not returning anything from .map.
You can check the fixed version: https://stackblitz.com/edit/react-pgtpnu?file=src%2FApp.js
You can't save files on server if you are using NextJS and you deploy in a serverless environment, you need to use a cloud service, you could use firestore to save base64 strings, or even better, upload the blobs directly to cloudinary, through multer middleware nextJS serverless functions let you write such a function in a few lines.
Saving images in the public directory is not a good approach you should try cloud computing applications such as AWS, Google, or Cloudinary. but I would prefer using Cloudinary because you can store approximately 10GB of images in a free account and also it is easy to integrate with react applications.
How does it work?
1- save your image in Cloudinary through API request then Cloudinary returns the link of the image in response.
2-store the link of the image inside the database
tutorial => upload image cloudinary and react
I have a PERN JS app and from the front (in react) a form has an input type file that sends the file (an image) to the server side. I then uploaded the image in a bucket in google cloud storage with public permission for everything to allUsers. It uploads fine, if I go to the public url provided by google storage i can see the image fine even on incognito window. The problem is when i send the path to a react component to display the image. It has a img html tag that goes to the alternative text property of img html tag and the component never displays the image i want. It uploads with a strange size of 20 B in Google Cloud Sotorage Bucket.
My code:
const router = require('express').Router();
const {Storage} = require('#google-cloud/storage');
const gc = new Storage({
projectId: GOOGLE_CLOUD_PROJECT_ID,
keyFilename: GOOGLE_CLOUD_KEYFILE,
})
getPublicUrl = (bucketName, fileName) => `https://storage.googleapis.com/best-buds/${bucketName}/${fileName}`
router.post('/', async (req, res, next) => {
try {
const file = req.files && req.files.image
const bucket = gc.bucket('best-buds');
const file_bucket = file && bucket.file(file.name)
const stream = file_bucket.createWriteStream({
resumable: false,
gzip: true
})
stream.on('finish', () => {
file.cloudStorageObject = file.name;
return file_bucket.makePublic()
.then(() => {
file.gcsUrl = getPublicUrl('best-buds',file.name);
next()
})
})
stream.end(file.buffer);
...
res.sendStatus(200);
} catch (error) {
next(error);
res.sendStatus(500);
}
});
module.exports = router;
I used devtools extension and checked my react component receives de props image with the correct url. If i go to that url using the browser i can see the image but still its not displaying in my component.
Could anyone help me?
The problem here is the upload, uploading files to google cloud storage, whether that be cloud storage or firebase storage, you will need to pass the file as blob and then you will need to assign proper extension to it with proper metadata, every filetype has its own metadata, for example: a pdf document will have document/pdf or an image will have image/png or image/jpeg. If the upload fails and you get some low byte size file then that means that the upload failed and it is due to metadata really.
var metadata = {
contentType: 'image/jpeg',
};
Firebase's doc explains how it works here
Here I m implementing the image upload to database using Spring Boot and React. I have encountered Error parsing HTTP request header error.
Error:
Error parsing HTTP request header
java.lang.IllegalArgumentException: Invalid character found in method
name
[0x160x030x010x020x000x010x000x010xfc0x030x030x1f0xc4T0x880xe1T0x070x00[Ua0xf40x8b0x0a0x900x8c<}0xe20xf70x080xa90xdaO0xb3U0xc7g0xaf0xfb30xa8].
HTTP method names must be tokens
React
doit=(e)=>{
e.preventDefault();
let imagefile = document.querySelector('#input');
let formData = new FormData();
formData.append("image", imagefile.files[0]);
return axios.post('https://localhost:8080/fileupload', "image",formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
}
<form encType='multipart/form-data'>
<input id="input" type='file' accept="image/*"/>
<button onClick={this.doit} type='submit'>Submit</button>
</form>
Spring Boot
#PostMapping("/fileupload",consumes = MediaType.MULTIPART_FORM_DATA_VALUE))
public String fileUpload(#RequestParam("name") String name, #RequestParam MultipartFile file) {
try {
byte[] image = file.getBytes();
MyModel model = new MyModel(name, image);
int saveImage = myService.saveImage(model);
if (saveImage == 1) {
return "success";
} else {
return "error";
}
} catch (Exception e) {
return "error";
}
}
So actually this problem has to do with just the way you are sending over the file. Images and videos are not the same as json data. They are long strings of numbers or encoded text that create visual masterpieces on the screen. I don't understand all of it yet basically what you need to do is get the file location. like if use a file picker api and it lets you choose something to upload, and you can store that info in a variable that is what 'file' is
then use javascript's built in fetch method.
const genFunction = async (file) =>{
const response = await fetch(file)
const blob = await response.blob();
// then you need to send that blob to the server
try {
const result = await requestToServer(
//configuration stuff
contentType:'image/jpg' // specify that you are sending a image
// or whatever file type somehow
)
console.log(request) } catch (e) { ... } }
lol they did not teach me how to do this at coding bootcamp or whatever, I didnt realize there are more types and things to do for so long. I figured out how to make it work with Amplify storage, and react native if anyone needs that just ask a question and i'll provide a solution for that.
this guy talks allot about best method to convert stuff to the format you actually need it to be. and the solution that i provided is the slowest, but easy to understand.
http://eugeneware.com/software-development/converting-base64-datauri-strings-into-blobs-or-typed-array
Also you should checkout out:
https://docs.mongodb.com/manual/core/gridfs/
Store images in a MongoDB database //basically the same question
https://javabeat.net/mongodb-gridfs-tutorial/
I have made this mistake before I didn't know how to solve it, my help told me to start storing images on AWS s3 which is not what I was asking. I hope you figure it out.
My users should be able to upload their logo in my react APP,
Ideally what I want to do is upload the file somewhere IE host it and in the process of doing so, retrieve the URL for it so I can store that URL in the database along with the other settings!
My code for the user to drop the image is quite simple:
this.state = {
files: []
};
<DropZone
onDrop={(files, acceptedFiles, rejectedFiles) => {
this.setState({files: [...this.state.files, ...acceptedFiles]});
}}>
{uploadedFiles}
{fileUpload}
</DropZone>
Then when saving settings i want to call a function which as I said, Uploads the image somewhere and returns that URL so i can then use it to store in a DB.
saveDetails = () => {
// some code here that takes the this.state.files[0]
uploads it somewhere then returns the URL.. THEN i call a DB storage function storing that URL to then be accessed elsewhere?!
}
Is there a common, easy way to do this?
Thanks if you can help!
You want to use axios to post the image data. Use FileReader to read file. Read it as a base 64 image and send it to the server. To read file as a base 64:-
handleDrop(acceptedFiles){
const {onError,onChangeAvatar} = this.props;
const reader = new FileReader();
reader.onabort = ()=>onError("Profile picture reading is aborted!");
reader.onerror = ()=>onError("Error with uploaded file. Try again.");
reader.readAsDataURL(acceptedFiles[0]);
reader.onload = ()=>{
const base64Image = reader.result;
onChangeAvatar(base64Image);
};
}
Now you can use axios to post image:-
onChangeAvatar (base64Image){
Axios.post("/url/to?upload",base64Image).then(response=>console.log(response))
}
save the file and return saved url from server side.
I'm trying to learn more about working with files for an upcoming project. Is there a way with react-dropzone that I can run a function when onDrop happens to change the contents of the files I'm uploading? For example, if I'm uploading a word doc that says "Hi everybody" how would I change the content to "Hi Dr. Nick"?
I've tried just accessing the data by using the filereader api after before attempting to make the changes. I tried using filereader right after the opening curly bracket of the async function and wasn't able to get it to work.
import React from 'react';
import Dropzone from 'react-dropzone';
import { graphql } from 'react-apollo';
import gql from 'graphql-tag';
const FileUpload = ({
children, disableClick, channelId, mutate, style = {},
}) => (
<Dropzone
style={style}
className="ignore"
onDrop={async ([file]) => {
const response = await mutate({
variables: {
channelId,
file,
},
});
console.log(response);
}}
disableClick={disableClick}
>
{children}
</Dropzone>
);
const createFileMessageMutation = gql`
mutation($channelId: Int!, $file: File) {
createMessage(channelId: $channelId, file: $file)
}
`;
export default graphql(createFileMessageMutation)(FileUpload);
Any thoughts on how to access and modify the contents of the file are greatly appreciated! Thanks.
onDrop={async ([file]) => {
var reader = new FileReader();
reader.onload = function(e) {
var contents = e.target.result;
displayContents(contents);
};
reader.readAsText(file);
}}
What you can do on frontend is to read file content and display it, all manipulations with file content should be done on server side. Push your file using ajax to your server with list of informations you want to change and use for example in nodeJS fs = require('fs')to make file modifications.
Also please visit this post i see that guys provided some solutions for your problem:
Is it possible to write data to file using only JavaScript?
and here is a fidlle taken from above link: http://jsfiddle.net/o4rhg1xe/1/
In Summary, you can read text file content using code i have provided and then use method from link to create Blob object with content you want and such file can be downlaoded by browser, (see fiddle)
Still in my opinion file modifications shoudl be moved to back-end side, ans i cant see no usecase to make them on frontend side.