I'm trying to send an image to my server. I'm keep getting the error: Current request is not a multipart request. When i test it in Postman it works fine.
This is my html form:
function saveImageToProduct() {
var formData = new FormData(document.querySelector("#newImagesForm"));
var encData = new URLSearchParams(formData.entries());
fetch("/uploadFile", { method: 'POST', body: encData })
.then(response => Promise.all([response.status, response.json()]))
.then(function([status, myJson]) {
if (status == 200) {
console.log("succeed!");
} else {
console.log("failed!");
}
})
.catch(error => console.log(error.message));
return false;
}
<form enctype="multipart/form-data" novalidate="novalidate" id="newImagesForm" method="post">
<div>
<p>Selecteer een afbeelding:</p>
<input id="file" name="file" type="file"/>
</div>
<br>
<div>
<button id="button" onclick="return saveImageToProduct()" class="btn btn-lg btn-info btn-block">
<span>Voeg aanbieding toe</span>
</button>
</div>
</form>
Backend Java code:
#PostMapping("/uploadFile")
public ProductImage uploadFile(#RequestParam("file") MultipartFile file) {
String fileName = fileStorageService.storeFile(file);
String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
.path("/uploads/")
.path(fileName)
.toUriString();
return new ProductImage(fileName, fileDownloadUri,
file.getContentType(), file.getSize());
}
When i try to send the image i'm getting a 500 error in the backend:
2019-03-10 19:40:33.588 ERROR 5668 --- [io-9001-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Current request is not a multipart request] with root cause org.springframework.web.multipart.MultipartException: Current request is not a multipart request
When i do it in Postman it works fine like the following image shows:
Any idea what i'm doing wrong here? Thanks in advance
The code below should do the job:
You basically create a new Form object and append the file data to it.
You are able to add multiple data attributes to it by adding more "data.append" lines.
function uploadPicture() {
var input = document.querySelector('input[type="file"]')
console.log(productID);
var data = new FormData()
data.append('file', input.files[0])
fetch('/uploadFile/', {
method: 'POST',
body: data
})
.then(response => Promise.all([response.status, response.json()]))
.then(function([status, myJson]) {
if (status == 200) {
console.log("succeed!");
} else {
console.log("failed!");
}
})
.catch(error => console.log(error.message));
}
HTML:
<input type="file" name="file" id="fileinput">
<input type="submit" value="Upload" onclick="uploadPicture()">
You can try modifying it -
var formData = new FormData(document.querySelector("#newImagesForm")[0]);
Related
Any help appreciated. I've got an app that pulls data from google books api. From each book page, the user is able to leave a review. The path to the review is /review/${isbn Number}. Each page has a path based on the isbn. The review routes work and I'm able to make the post request through insomnia/postman with no issues, I'm just having trouble with the front-end js in pulling the data from the input boxes to make the post request. I'm not sure if the issue is because the isbn being in the path. Below is my front-end javascript that I am unable to fix.
const newFormHandler = async (event) => {
event.preventDefault();
console.log("testing")
const description = document.querySelector('#description').value;
const reviewTitle = document.querySelector('#reviewTitle').value;
const isbn = window.location.search
if (description) {
const response = await fetch(`api/review/${isbn}`, {
method: 'POST',
body: JSON.stringify({ description, reviewTitle }),
headers: {
'Content-Type': 'application/json',
},
});
if (response.ok) {
document.location.reload();
} else {
alert('Failed to create review');
}
}
};
document
.querySelector('.form-group')
.addEventListener('submit', newFormHandler);
My form is below:
<div class="col form-group">
<div class ="card reviewCard" style = "background-color:#fcf8f3; color: #65625e;">
<form id="blog-form">
<div>
<label for="reviewTitle">Review Title</label>
<input
value="{{title}}"
id="reviewTitle"
name="reviewtitle"
placeholder="Enter Review Title"
type="text"
required="required"
class="form-control"
data-bv-notempty="true"
data-bv-notempty-message="The title cannot be empty"
/>
</div>
<div>
<label for="review">Review</label>
<textarea
id="description"
name="review"
cols="40"
rows="10"
required="required"
class="form-control"
>{{description}}</textarea>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
</div>
</div>
</div>
And here is my route that works fine with insomnia, no issues.
router.get('/review/:id', async (req, res) => {
try {
const isbn13 = req.params['id'];
const reviewData = await Review.findAll({ where: {
isbn:isbn13
},
include: [
{
model: User,
attributes: ['name'],
}
]
})
const reviews = reviewData.map((review) => review.get({ plain:true}));
// console.log(isbn13);
res.render('review', {
isbn: isbn13, reviews:reviews
});
} catch (err) {
console.log(err)
}
});
Any help appreciated. I tried to pull in the isbn number from the path, but with no success. I think I have it formatted wrong somehow.
First console log your req
You should see the body containing some data.
In a get request the they are arguments in the URL.
In a Psot request they are in the body of the request.
Description
I have a table, where i collect values from checkboxes with JavaScript. This values should be send to a protected API route in a Laravel backend.
I use the standard Laravel auth setup (out of the box).
Question
What do I have to send with the JavaScript post request for authentication and how do i do that? Can i add a auth token or something like that to the headers?
At the moment i get the reponse:
"This action is unauthorized".
exception: "Symfony\\Component\\HttpKernel\\Exception\\AccessDeniedHttpException"
Edit
At the current point of my research the api token seems to be a simple solution for my case. But i can't figure out how to attach the api token to the JavaScript post request.
Thats the JavaScript function for collecting the values storing them in objects.
import SaveData from "../api/SaveData";
export default async function SaveMultipleReports() {
const table = document.getElementById("reports-dashboard");
const rows = table.querySelectorAll("div[class=report-tr]");
let reports = [];
for (const row of rows) {
const checkbox_visible = row.querySelector("input[name=visible]")
.checked;
const checkbox_slider = document.querySelector(
"input[name=show_in_slider]"
).checked;
const report = {
id: row.id,
visible: checkbox_visible,
show_in_slider: checkbox_slider
};
reports.push(report);
}
console.log(reports);
const response = await SaveData("/api/reports/update", reports);
console.log(response);
}
And that is the SavaData function:
export default async function SaveData(api, data) {
const token = document
.querySelector('meta[name="csrf-token"]')
.getAttribute("content");
const url = window.location.origin + api;
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRF-TOKEN": token,
Accept: "application/json"
},
body: JSON.stringify(data)
});
const result = await response.json();
return result;
}
And thats the line in the api.php:
Route::middleware("can:administration")->post("reports/update", "ReportsController#UpdateAll");
The whole repo is here.
Thanks for your time in advance :)
Edit 2
For now i managed it without JavaScript. Put all the values, i want to update in form and load a hidden input for the ID of every object (the ID is needed for the controller afterwards).
Thanks to this post.
{!! Form::open(["route" => ["admin.reports.multiupdate"], "method" => "PUT", "class" => "report-table"]) !!}
... // some HTML
#foreach ($reports as $report)
<div class="report-tr">
<input type="hidden" name="reports[{{$loop->index}}][id]" value="{{$report->id}}">
<div class="td-name">
<p class="td-text">{{$report->name}}</p>
</div>
<div class="td-flex">{{$report->body}}</div>
<div class="tr-wrapper">
<div class="checkbox-visible">
<div class="checkbox-container">
<input class="checkbox" type="checkbox" name="reports[{{$loop->index}}][visible]" value="1" checked>
<span class="checkmark"></span>
</div>
<label class="table-label" for="visible">Sichtbar</label>
</div>
<div class="checkbox-slider">
<div class="checkbox-container">
<input class="checkbox" type="checkbox" name="reports[{{$loop->index}}][show_in_slider]" value="1"
{{($report->show_in_slider == 1 ? "checked" : "")}}>
<span class="checkmark"></span>
</div>
<label class="table-label" for="show_in_slider">Im Slider</label>
</div>
<div class="td-buttons">
...
#endforeach
<button class="floating-save">
#svg("saveAll", "saveAll")
</button>
{!! Form::close() !!}
And a snippet from the Controller:
public function MultipleUpate(ReportUpdate $request)
{
$reports = $request->input("reports");
foreach ($reports as $row) {
$report = Report::find($row["id"]);
// giving the checkbox 0, if it isn't checked
$isVisible = isset($row["visible"]) ? 1 : 0;
$inSlider = isset($row["show_in_slider"]) ? 1 : 0;
$report->visible = $isVisible;
$report->show_in_slider = $inSlider;
$report->new = false;
if ($report->save()) {
$saved = true;
}
}
if ($saved == true) {
$request->session()->flash("success", "Änderungen gespeichert!");
} else {
$request->session()->flash("error", "Das hat nicht geklappt!");
}
return back();
The ReportUdpate function contains only that:
public function authorize()
{
return true;
}
public function rules()
{
return [
"visible" => "nullable",
"show_in_slider" => "nullable"
];
}
You are talking about authentication but using an authorization middleware. There is a difference between the two.
Read about it here: https://medium.com/datadriveninvestor/authentication-vs-authorization-716fea914d55
With that being said, what you are looking for is an authentication middleware that protects your routes from unauthenticated users. Laravel provides a middleware called Authenticate out of the box for this specific purpose.
Change your route to be like so:
Route::middleware("auth")->post("reports/update", "ReportsController#UpdateAll");
Upload images and form content? How to upload? The idea is to upload it to the client and then upload it to the server along with the form content, right?
I want to upload the form content and the image to the server when I click submit, instead of uploading the image separately when I upload the image.
But I don't know how to upload at the same time. Can you help me?
<template>
<form>
<input type="text" v-model="test">
<img :src="previewImage" class="uploading-image" />
<input type="file" accept="image/jpeg" #change=uploadImage>
<input type="submit"></input>
</form>
</template>
export default {
data(){
return{
previewImage:null,
test: ''
}
},
methods:{
uploadImage(e){
const image = e.target.files[0];
const reader = new FileReader();
reader.readAsDataURL(image);
reader.onload = e =>{
this.previewImage = e.target.result;
console.log(this.previewImage);
};
const URL = 'http://xxxx';
let data = new FormData();
data.append('name', 'my-picture');
data.append('file', event.target.files[0]);
let config = {
header : {
'Content-Type' : 'image/png'
}
}
axios.put(URL, data,config).then(response => {
console.log('image upload response > ', response)
})
}
}
You need to add this to the form
<form #submit.prevent="uploadImage">
<input type="text" v-model="test">
<img :src="previewImage" class="uploading-image" />
<input type="file" accept="image/jpeg" >
<input type="submit"></input>
</form>
I am trying to retrieve data from a Bootstrap form element, and save it to a PostgresSQL database using Express and Knex. There are no errors when I run the route; however, the data from the form is saved as null. Here is my form element (I'm using React):
render() {
return (
<form>
<div className ="form-group">
<label>Add a Note:</label>
<textarea className="form-control" name="note" rows="5">
</textarea>
</div>
<button onClick={this.handleClick} className="btn btn-primary"
type="submit">Submit</button>
</form>
)
}
Here is my fetch to the POST route:
handleClick(e) {
e.preventDefault()
fetch('/create-note', {
method: 'POST'
})
}
Here is my Express POST route (app.use(bodyParser.json()) is included in this file):
app.post('/create-note', (req, res) => {
postNote(req.body.note)
.then(() => {
res.sendStatus(201)
})
})
Here is the Knex postNote function:
export function postNote(newNote) {
const query = knex
.insert({ note_content: newNote })
.into('notes')
return query
}
Any help would be appreciated!
With POST requests you may have to wait for data body to be ready. Try this
app.post('/create-note', (req, res) => {
var body = '';
request.on('data',function(data) { body += data; });
request.on('end', function(data) {
postNote(body)
.then(() => {
res.sendStatus(201)
})
});
})
try the following in your markup, and forgo using fetch
...
<form method="POST" action="/create-note" enctype='application/json'>
...
</form>
...
or since the default encoding for a form is application/x-www-form-encoded (doc), add the following middleware to your express app..
...
app.use(bodyParser.urlencoded({ extended: true }));
...
also you could try...
...
<button ref="form" onClick={this.handleClick} className="btn btn-primary"
type="submit">Submit</button>
...
along with
handleClick(e) {
e.preventDefault();
const data = new FormData(this.refs.form);
fetch('/create-note', {
method: 'POST',
body: data
})
}
I found a solution and want to post it incase anyone else runs into a similar issue. The problem was I wasn't querying textarea's value correctly, so I was passing an undefined variable to the database to save.
Here's the solution I came up with:
handleSubmit(e) {
const data = new FormData(e.target)
const text = {note: data.get('note')}
fetch('/create-note', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(text)
})
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className ="form-group">
<label>Add a Note:</label>
<textarea className="form-control" name="note" rows="5">
</textarea>
<button ref="textarea" className="btn btn-primary"
type="submit">Submit</button>
</div>
</form>
)
}
I put a onSubmit event listener on the form, and created a new FormData instance with the form. Then I created an object containing the value of the textarea to pass into the fetch call.
I'm trying to upload multiple files to server.
The file is being stored in a variable.
When I click upload the client is sending that variable empty.
Here is my html
<div class = "control-group form-group col-md-12"
ng-class = "{'has-error':newAsset.OSGImages.$invalid && newAsset.OSGImages.$dirty}" ng-if = "showUploadFile(4)">
<label>OSG Images (max 3 MB)</label>
<input type="file" multiple ngf-select="" ng-model="newAssetForm.OSGImages" name = "OSGImages" ngf-max-size="3 MB">
<p ng-repeat="image in newAssetForm.OSGImages">
{{image.name}}
</p>
<span class = "help-block has-error" ng-if="newAsset.OSGImages.$dirty">
</span>
</div>
Here is my js code:
enter code var fileReader = new FileReader();
fileReader.readAsArrayBuffer($scope.newAssetForm.OSGImages[0]);
fileReader.onload = function(e) {
console.log(e);
Upload.upload({
url: '/api/uploadAsset',
headers: {
'Content-Type': 'multipart/form-data'
},
data: {
'projectId': $scope.projectId,
'loadValueType' : $scope.newAssetForm.loadValueType,
'outputVideoLink': $scope.newAssetForm.outputVideoLink,
'isActive': $scope.newAssetForm.isActive,
'PImageSet': PImageSet,
inputImageUrl: $scope.newAssetForm.inputImageUrl,
markerPattFile: $scope.newAssetForm.markerPattFile,
cinema: $scope.newAssetForm.cinema,
objFile: $scope.newAssetForm.objFile,
mtlFile: $scope.newAssetForm.mtlFile,
PImage: $scope.newAssetForm.PImage,
osgFile: $scope.newAssetForm.OSGFile,
osgImage: e.target.result,
},
})
.then(function onSuccess(result){
$scope.$emit('create_asset', result.data);
$modalInstance.close();
})
I tried uploading with postman and the server is getting the files.
Also, the console logs print the files correctly.
Why the client is sending empty variable?