React - Axios POST form data with files and strings - reactjs

I had to create Axios POST where the body type is form-data. Some of keys are strings, and some are files. Postman request:
How to add upload buttons to fetch files into state, and how to make Axios request?

Simply trigger a method in onChange event on input of type "file" and send to server with "multipart/form-data" format:
<Input id="file" type="file" onChange={this.uploadFile} />
let formData = new FormData();
/*
Iteate over any file sent over appending the files
to the form data.
*/
for( var i = 0; i < this.files.length; i++ ){
let file = this.files[i];
formData.append('files[' + i + ']', file);
}
/*
Make the request to the POST /select-files URL
*/
axios.post( '/select-files',
formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(function(){
console.log('SUCCESS!!');
})
.catch(function(){
console.log('FAILURE!!');
});

import React, { Component } from 'react';
import axios from "axios";
class FileUpload extends Component {
// API Endpoints
custom_file_upload_url = `YOUR_API_ENDPOINT_SHOULD_GOES_HERE`;
constructor(props) {
super(props);
this.state = {
image_file: null,
image_preview: '',
}
}
// Image Preview Handler
handleImagePreview = (e) => {
let image_as_base64 = URL.createObjectURL(e.target.files[0])
let image_as_files = e.target.files[0];
this.setState({
image_preview: image_as_base64,
image_file: image_as_files,
})
}
// Image/File Submit Handler
handleSubmitFile = () => {
if (this.state.image_file !== null){
let formData = new FormData();
formData.append('customFile', this.state.image_file);
// the image field name should be similar to your api endpoint field name
// in my case here the field name is customFile
axios.post(
this.custom_file_upload_url,
formData,
{
headers: {
"Authorization": "YOUR_API_AUTHORIZATION_KEY_SHOULD_GOES_HERE_IF_HAVE",
"Content-type": "multipart/form-data",
},
}
)
.then(res => {
console.log(`Success` + res.data);
})
.catch(err => {
console.log(err);
})
}
}
// render from here
render() {
return (
<div>
{/* image preview */}
<img src={this.state.image_preview} alt="image_preview"/>
{/* image input field */}
<input
type="file"
onChange={this.handleImagePreview}
/>
<label>Upload file</label>
<input type="submit" onClick={this.handleSubmitFile} value="Submit"/>
</div>
);
}
}
export default FileUpload;

Related

I am trying to make a post request in a API from React but i get "net::ERR_ABORTED 415"

here is the code and here is the web api that i am connecting to "https://hub.graphistry.com/api-token-auth/", i have try to use axios but id doesn't help with the cors
import React, { Component } from "react";
export default class App extends Component {
async postData() {
try {
let result = await fetch("https://hub.graphistry.com/api-token-auth/", {
method: "post",
mode: "no-cors",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
username: "orlando",
password: "graphistry1234",
}),
});
console.log(result);
} catch (e) {
console.log(e);
}
}
render() {
return (
<div>
<button onClick={() => this.postData()}>
Press me to post some data
</button>
</div>
);
}
}
In this case, you need to use form-data as bellow:
let formData = new FormData();
formData.append("username", "orlando");
formData.append("password", "graphistry1234");
fetch("https://hub.graphistry.com/api-token-auth/", {
method: "POST",
body: formData
})
fetch() does not expect a JavaScript object at body. curl command and fetch() pattern are not the same.

React axios file upload failing - error "Multipart: Boundary not found"

My code isn't working as it should, it keeps receiving a 400 from the server and failing to upload. I must be making mistakes in the react component so please can you take a look for me? All's working in Postman, so the backend code seems fine.
import React, { useState } from "react";
import axios from "axios";
const UploadAvatar = () => {
const [image, setImage] = useState();
const handleUpload = async (e) => {
e.preventDefault();
const config = {
headers: {
"content-type": "multipart/form-data",
Authorization: localStorage.getItem("token"),
},
};
try {
const formData = new FormData();
formData.append("avatar", image);
const response = await axios.post(
"/users/me/avatar",
{ formData },
config
);
console.log(response);
} catch (err) {
console.error(err.message);
}
};
return (
<div>
<form onSubmit={handleUpload}>
Select image to upload:
<input
type="file"
onChange={(e) => setImage(e.target.value)}
name="fileToUpload"
/>
<input type="submit" value="Upload Image" name="submit" />
</form>
</div>
);
};
export default UploadAvatar;
There some things you need to do.
This is not related to the problem, but I think it is worth checking:
const config = {
headers: {
"content-type": "multipart/form-data",
Authorization: localStorage.getItem("token"),
},
}
What scheme is your Authorization (Basic, Bearer, OAuth)?
. If its a Bearer schema (e.g.), is your localStorage.getItem("token") returning only the token or is returning "Bearer {token}"? For bearer token, you need to include the word 'Bearer' before the token.
The content-type it's not really necessary here, but you can let it there if you prefer.
In your code, you need to do some changes:
In your handleUpload you need to do this:
try {
const formData = new FormData();
formData.append("avatar", image);
// I just removed the curly brackets from formData
const response = await api.post("/users/me/avatar", formData, config);
console.log(response);
} catch (err) {
console.error(err.message);
}
And in your input file type:
<input
type="file"
onChange={(e) => setImage(e.target.files[0])}
name="fileToUpload"
/>
For input file types, the target should be e.target.files, wich returns a list of files and each file is a FileList object. As you sending only one image you can set it as e.target.files[0] to get the first image.
And that´s all. It should work now! :)
I did a poc here and everything goes ok.
for bad request
it happens because of axios ,
your not sending json data
in your code
const response = await axios.post(
"/users/me/avatar",
{ formData },<---------here is the problem object
formData ,<-------try without curly brazes or use below detailed axios
config
);
console.log(response);
} catch (err) {
console.error(err.message);
}
};
change axios
axios({
method: 'post',
url: 'myurl',
data: formData ,
headers: {'Content-Type': 'multipart/form-data' }
})
.then(function (response) {
//handle success
console.log(response);
})
.catch(function (response) {
//handle error
console.log(response);
});
another problem
YOUR SENDING FILES
<input
type="file"
onChange={(e) => setImage(e.target.value)}<-------wrong e.target.files[0]
name="fileToUpload"
/>
change
if u sending mutliple files
e.target.files
or if you sending single file use
e.target.files[0]
change code
<input type="file"
onChange={(e) => setImage(e.target.files[0])}
name="fileToUpload"
/>

How to file upload React js web api not work

I am working on file upload React with web API. After uploading the file, server side shows that
null.,..................................................................
import React, { PropTypes } from 'react';
import axios from 'axios';
class Dashboard extends React.Component {
constructor(props){
var files;
super(props);
this.state = {
selectedFile: null
}
}
fileChangedHandler = event => {
this.setState({
selectedFile: event.target.files[0]
})
var file = this.refs.file.files[0].name;
let reader = new FileReader();
reader.onloadend = () => {
this.setState({
imagePreviewUrl: reader.result
});
}
reader.readAsDataURL(event.target.files[0])
}
async submit(e){
e.preventDefault();
await this.addImage(this.state.selectedFile);
};
addImage = async (file) => {
console.log(this.state.selectedFile);
await fetch('http://localhost:32188/Api/Authenticate/Uploadfile',
{
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: this.state.selectedFile
}
)
}
render() {
<form onSubmit={e => this.submit(e)} enctype="multipart/form-data">
<input ref="file" type="file" name="user[image]" onChange={this.fileChangedHandler} style={{padding: '5px', marginLeft: '31px'}} />
<div className="signin_form_button">
<input type="submit" value="Upload" className="signin_form_buttonstyle" />
</div>
</form>
}
}
Serverside Code
Model
public class ImageModel
{
public IFormFile File { get; set; }
}
Controller
[System.Web.Http.Route("Api/Authenticate/Uploadfile")]
[System.Web.Http.HttpPost]
public void CreateImage([System.Web.Http.FromBody] ImageModel model)
{
var file = model.File;
}
Following Error Message is displayed
500 Internal Server Error Occurred
Message: "An error has occurred."
ExceptionMessage: "Object reference not set to an instance of an object."
Please Help.
Link:https://codesandbox.io/s/vigorous-mestorf-osf90

React authentication with JWT

I am trying to add an authentication system to my application in React / Laravel. For that I make a request for the theory recovers a token as on Passport. The problem is that it returns me a token undefined ... Yet when I look at the console of my browser I see in preview the token in question ...
Can someone please guide me to solve this problem?
Here is the code of my Auth service
import decode from 'jwt-decode';
export default class AuthService {
// Initializing important variables
constructor(domain) {
this.domain = domain || 'http://127.0.0.1:8000' // API server
domain
this.fetch = this.fetch.bind(this) // React binding stuff
this.login = this.login.bind(this)
this.getProfile = this.getProfile.bind(this)
}
login(username, password) {
// Get a token from api server using the fetch api
return this.fetch(`${this.domain}/oauth/token`, {
method: 'POST',
body: JSON.stringify({
username,
password,
grant_type: "password",
client_id:"2",
client_secret : "Wu07Aqy9pU5pLO9ooTsqYDBpOdzGwrhvw5DahcEo"
})
}).then(res => {
this.setToken(res.token) // Setting the token in localStorage
return Promise.resolve(res);
})
}
loggedIn() {
// Checks if there is a saved token and it's still valid
const token = this.getToken() // GEtting token from localstorage
return !!token && !this.isTokenExpired(token) // handwaiving here
}
isTokenExpired(token) {
try {
const decoded = decode(token);
if (decoded.exp < Date.now() / 1000) { // Checking if token is
expired. N
return true;
}
else
return false;
}
catch (err) {
return false;
}
}
setToken(token) {
// Saves user token to localStorage
localStorage.setItem('access_token', token)
}
getToken() {
// Retrieves the user token from localStorage
return localStorage.getItem('access_token')
}
logout() {
// Clear user token and profile data from localStorage
localStorage.removeItem('access_token');
}
getProfile() {
// Using jwt-decode npm package to decode the token
return decode(this.getToken());
}
fetch(url, options) {
// performs api calls sending the required authentication headers
const headers = {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
// Setting Authorization header
// Authorization: Bearer xxxxxxx.xxxxxxxx.xxxxxx
if (this.loggedIn()) {
headers['Authorization'] = 'Bearer ' + this.getToken()
}
return fetch(url, {
headers,
...options
})
.then(this._checkStatus)
.then(response => response.json())
}
_checkStatus(response) {
// raises an error in case response status is not a success
if (response.status >= 200 && response.status < 300) { // Success
status lies between 200 to 300
return response
} else {
var error = new Error(response.statusText)
error.response = response
throw error
}
}
}
Here of my form
import React, { Component } from 'react';
import AuthService from './AuthService';
import { Router, Route, Switch, Link } from 'react-router-dom'
class Login extends Component {
constructor(){
super();
this.handleChange = this.handleChange.bind(this);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
this.Auth = new AuthService();
}
handleFormSubmit(e){
e.preventDefault();
this.Auth.login(this.state.username,this.state.password)
.then(res =>{
this.props.history.replace('/Localisations');
})
.catch(err =>{
alert(err);
})
}
componentWillMount(){
if(this.Auth.loggedIn())
this.props.history.replace('/');
}
render() {
return (
<div className="center">
<div className="card">
<h1>Login</h1>
<form onSubmit={this.handleFormSubmit}>
<input
className="form-item"
placeholder="Username goes here..."
name="username"
type="text"
onChange={this.handleChange}
/>
<input
className="form-item"
placeholder="Password goes here..."
name="password"
type="password"
onChange={this.handleChange}
/>
<input
className="form-submit"
value="Submit"
type="submit"
/>
</form>
</div>
</div>
);
}
handleChange(e){
this.setState(
{
[e.target.name]: e.target.value
}
)
}
}
export default Login;
And here of of my with Auth
import React, { Component } from 'react';
import AuthService from './AuthService';
export default function withAuth(AuthComponent) {
const Auth = new AuthService('http://127.0.0.1:8000');
return class AuthWrapped extends Component {
constructor() {
super();
this.state = {
user: null
}
}
componentWillMount() {
if (!Auth.loggedIn()) {
this.props.history.push('/Localisations')
}
else {
try {
const profile = Auth.getProfile()
this.setState({
user: profile
})
}
catch(err){
Auth.logout()
this.props.history.push('/')
}
}
}
render() {
if (this.state.user) {
return (
<AuthComponent history={this.props.history} user= .
{this.state.user} />
)
}
else {
return null
}
}
};
}

React.js, how to send a multipart/form-data to server

We want to send an image file as multipart/form to the backend, we try to use html form to get file and send the file as formData, here are the codes
export default class Task extends React.Component {
uploadAction() {
var data = new FormData();
var imagedata = document.querySelector('input[type="file"]').files[0];
data.append("data", imagedata);
fetch("http://localhost:8910/taskCreationController/createStoryTask", {
mode: 'no-cors',
method: "POST",
headers: {
"Content-Type": "multipart/form-data"
"Accept": "application/json",
"type": "formData"
},
body: data
}).then(function (res) {
if (res.ok) {
alert("Perfect! ");
} else if (res.status == 401) {
alert("Oops! ");
}
}, function (e) {
alert("Error submitting form!");
});
}
render() {
return (
<form encType="multipart/form-data" action="">
<input type="file" name="fileName" defaultValue="fileName"></input>
<input type="button" value="upload" onClick={this.uploadAction.bind(this)}></input>
</form>
)
}
}
The error in backend is "nested exception is org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found".
After reading this, we tried to set boundary to headers in fetch:
fetch("http://localhost:8910/taskCreationController/createStoryTask", {
mode: 'no-cors',
method: "POST",
headers: {
"Content-Type": "multipart/form-data; boundary=AaB03x" +
"--AaB03x" +
"Content-Disposition: file" +
"Content-Type: png" +
"Content-Transfer-Encoding: binary" +
"...data... " +
"--AaB03x--",
"Accept": "application/json",
"type": "formData"
},
body: data
}).then(function (res) {
if (res.ok) {
alert("Perfect! ");
} else if (res.status == 401) {
alert("Oops! ");
}
}, function (e) {
alert("Error submitting form!");
});
}
This time, the error in backend is: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException] with root cause
Do we add the multipart boundary right? Where should it be?
Maybe we are wrong at first because we don't get the multipart/form-data. How can we get it correctly?
We just try to remove our headers and it works!
fetch("http://localhost:8910/taskCreationController/createStoryTask", {
mode: 'no-cors',
method: "POST",
body: data
}).then(function (res) {
if (res.ok) {
alert("Perfect! ");
} else if (res.status == 401) {
alert("Oops! ");
}
}, function (e) {
alert("Error submitting form!");
});
Here is my solution for image upload with preview through axios.
import React, { Component } from 'react';
import axios from "axios";
React Component Class:
class FileUpload extends Component {
// API Endpoints
custom_file_upload_url = `YOUR_API_ENDPOINT_SHOULD_GOES_HERE`;
constructor(props) {
super(props);
this.state = {
image_file: null,
image_preview: '',
}
}
// Image Preview Handler
handleImagePreview = (e) => {
let image_as_base64 = URL.createObjectURL(e.target.files[0])
let image_as_files = e.target.files[0];
this.setState({
image_preview: image_as_base64,
image_file: image_as_files,
})
}
// Image/File Submit Handler
handleSubmitFile = () => {
if (this.state.image_file !== null){
let formData = new FormData();
formData.append('customFile', this.state.image_file);
// the image field name should be similar to your api endpoint field name
// in my case here the field name is customFile
axios.post(
this.custom_file_upload_url,
formData,
{
headers: {
"Authorization": "YOUR_API_AUTHORIZATION_KEY_SHOULD_GOES_HERE_IF_HAVE",
"Content-type": "multipart/form-data",
},
}
)
.then(res => {
console.log(`Success` + res.data);
})
.catch(err => {
console.log(err);
})
}
}
// render from here
render() {
return (
<div>
{/* image preview */}
<img src={this.state.image_preview} alt="image preview"/>
{/* image input field */}
<input
type="file"
onChange={this.handleImagePreview}
/>
<label>Upload file</label>
<input type="submit" onClick={this.handleSubmitFile} value="Submit"/>
</div>
);
}
}
export default FileUpload;
The file is also available in the event:
e.target.files[0]
(eliminates the need for document.querySelector('input[type="file"]').files[0];)
uploadAction(e) {
const data = new FormData();
const imagedata = e.target.files[0];
data.append('inputname', imagedata);
...
Note:
Use console.log(data.get('inputname')) for debugging, console.log(data) will not display the appended data.
https://muffinman.io/uploading-files-using-fetch-multipart-form-data/ worked best for me. Its using formData.
import React from "react";
import logo from "./logo.svg";
import "./App.css";
import "bootstrap/dist/css/bootstrap.min.css";
import Button from "react-bootstrap/Button";
const ReactDOM = require("react-dom");
export default class App extends React.Component {
constructor(props) {
super(props);
this.test = this.test.bind(this);
this.state = {
fileUploadOngoing: false
};
}
test() {
console.log(
"Test this.state.fileUploadOngoing=" + this.state.fileUploadOngoing
);
this.setState({
fileUploadOngoing: true
});
const fileInput = document.querySelector("#fileInput");
const formData = new FormData();
formData.append("file", fileInput.files[0]);
formData.append("test", "StringValueTest");
const options = {
method: "POST",
body: formData
// If you add this, upload won't work
// headers: {
// 'Content-Type': 'multipart/form-data',
// }
};
fetch("http://localhost:5000/ui/upload/file", options);
}
render() {
console.log("this.state.fileUploadOngoing=" + this.state.fileUploadOngoing);
return (
<div>
<input id="fileInput" type="file" name="file" />
<Button onClick={this.test} variant="primary">
Primary
</Button>
{this.state.fileUploadOngoing && (
<div>
<h1> File upload ongoing abc 123</h1>
{console.log(
"Why is it printing this.state.fileUploadOngoing=" +
this.state.fileUploadOngoing
)}
</div>
)}
</div>
);
}
}
React File Upload Component
import { Component } from 'react';
class Upload extends Component {
constructor() {
super();
this.state = {
image: '',
}
}
handleFileChange = e => {
this.setState({
[e.target.name]: e.target.files[0],
})
}
handleSubmit = async e => {
e.preventDefault();
const formData = new FormData();
for (let name in this.state) {
formData.append(name, this.state[name]);
}
await fetch('/api/upload', {
method: 'POST',
body: formData,
});
alert('done');
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input
name="image"
type="file"
onChange={this.handleFileChange}>
</input>
<input type="submit"></input>
</form>
)
}
}
export default Upload;
the request was rejected because no multipart boundary was found".
When you send multipart/form-data, the boundary is automatically added to a content-type of a request header. you have to tell the server when the parameter ends with the boundary rule. You had to set the Content-type like this
"Content-Type": `multipart/form-data: boundary=add-random-characters`
This article with guide you: https://roytuts.com/boundary-in-multipart-form-data/
The boundary is included to separate name/value pair in the
multipart/form-data. The boundary parameter acts like a marker for
each pair of name and value in the multipart/form-data. The boundary
parameter is automatically added to the Content-Type in the http
(Hyper Text Transfer Protocol) request header.
For sending multipart/formdata, you need to avoid contentType, since the browser automatically assigns the boundary and Content-Type.
In your case by using fetch, even if you avoid Content-Type it sets to default text/plain. So try with jQuery ajax. which removes the contentType if we set it to false.
This is the working code
var data = new FormData();
var imagedata = document.querySelector('input[type="file"]').files[0];
data.append("data", imagedata);
$.ajax({
method: "POST",
url: fullUrl,
data: data,
dataType: 'json',
cache: false,
processData: false,
contentType: false
}).done((data) => {
//resolve(data);
}).fail((err) => {
//console.log("errorrr for file upload", err);
//reject(err);
});

Resources