I am trying to submit a file asynchronously via Angular. This is the HTML:
<form ng-submit="videoSubmit()">
<input id="upl-0" type="file" name="upl" accept="video/ogg, video/mp4, video/webm">
<input type="submit" value='Submit' />
</form>
My Angular code:
$scope.videoSubmit = function() {
var file = document.getElementById('upl-0').files[0];
var formData = new FormData();
console.log(file);
formData.append("upl", file, file.name);
console.log(formData);
console.log(formData.getAll("upl"));
$http({
method: 'POST',
url: "api/asset/upload-test",
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
.then(function(result) {
console.log(result);
});
};
This definitely attaches the file to the formData object because it is displaying the right file data in the console.
Now I want to do something with this on the server, but in the meantime I just want to actually get this working, so this is all that's on the server:
router.post('/api/asset/upload-test', function(req, res) {
console.log(req.data);
console.log(req.body);
});
However somehow the server just doesn't receive the file, and displays undefined for req.data and {} for req.body. Why is this and how can I get this actually working in the same implementation, so without having to encode or decode the file in something like base64 or similar. Thanks.
should be in req.files and in order for that you'll need to use express.bodyParser(). If you use express of course.
Related
I have a Node/Express app and i want to sent a file with a form, i want to send it with ajax so i can process the server response.
So far my form is:
<form method='POST' enctype='multipart/form-data' id='excelform'>
<input type='file' id='target_file' name='target_file' required>
</form>
<button class='btn btn-menu3 align-self-end' onClick='excel_email9f();'>Enviar</button>
i have a button that calls the following function for an ajax request:
function excel_email9f(){
var data = new FormData();
var file = $('#target_file')[0].files[0];
data.append('file', file);
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
url: "/Excelemail9f",
data: data,
processData: false,
contentType: false,
cache: false,
timeout: 600000,
success: function (data) {
var response = data.q0;
alert(response);
},
error: function (e) {
console.log("ERROR : ", e);
}
});
};
i can access the file and its properties like name.
On server side i have this route
app.post('/Excelemail9f',function(req,res){
// checking req.files is empty or not
if (Object.keys(req.files).length == 0) {
return res.status(400).send('No files were uploaded.');
}
console.log('name: ' + req.files.target_file.name);
let target_file = req.files.target_file;
// target_file.mv(path, callback)
target_file.mv(path.join(__dirname, 'uploads', target_file.name), (err) => {
if (err) throw err;
res.send(JSON.stringify({q0 : 0}));
})
})
How do i access the file on the server side, i use req.files.target_file but i get the following error:
TypeError: Cannot read property 'name' of undefined
You're posting the data as a FormData object, but you're referring to the HTML input element's ID as the filename. You populate the FormData object by calling data.append('file', file);, so you need to reference it by req.files.file rather than req.files.target_file.
I generate a pre-signed URL for uploading files to AWS S3 via a Python-backed API. This part receives filename info once the user selects the file in a browser (see below), and returns a JSON payload (see below) with the base URL and fields.
import logging
import boto3
from botocore.exceptions import ClientError
def create_presigned_post(bucket_name, object_name,
fields=None, conditions=None, expiration=3600):
# Generate a presigned S3 POST URL
s3_client = boto3.client('s3')
try:
response = s3_client.generate_presigned_post(bucket_name,
object_name,
Fields=fields,
Conditions=conditions,
ExpiresIn=expiration)
except ClientError as e:
logging.error(e)
return None
# The response contains the presigned URL and required fields
return response
Here's the JSON response I get from this function. (I changed/abbreviated some of the values, but you get the point.)
{
"url": "https://s3.us-east-2.amazonaws.com/my_bucket_name",
"fields": {
"key": "some.txt",
"AWSAccessKeyId": "ASI...",
"x-amz-security-token": "Ag9o...",
"policy": "eyJ...=",
"signature": "jn...="
}
}
Here's the HTML form that I'm using to upload the file. I have some vanilla Javascript that tracks changes to the form and updates the URL_VALUE for the form and the VALUE for each form item upon changes (e.g. file selection).
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<!-- Copy the 'url' value returned by S3Client.generate_presigned_post() -->
<form action="URL_VALUE" method="post" enctype="multipart/form-data">
<!-- Copy the 'fields' key:values returned by S3Client.generate_presigned_post() -->
<input type="hidden" name="key" value="VALUE" />
<input type="hidden" name="AWSAccessKeyId" value="VALUE" />
<input type="hidden" name="policy" value="VALUE" />
<input type="hidden" name="signature" value="VALUE" />
File:
<input type="file" name="file" /> <br />
<input type="submit" name="submit" value="Upload to Amazon S3" />
</form>
</body>
</html>
This HTML form works fine by itself, but I tried adding some Javascript (both vanilla and JQuery), so I can track file progress and disable form inputs until the upload is complete.
I can't get Javascript to work!!!
I have tried so many examples (again, both vanilla JS and JQuery).
Has anyone recently implemented this and can help?
It's even easier than what you've posted.
fetch(yourSignedUrl, {
method: 'PUT',
body: file,
headers: {
'Content-Type': file.type
}
}).then((res) => {
if (!res.ok) {
throw new Error(res.statusText);
}
return res.headers.get('ETag');
});
I believe you have to pass the AWS secrets such as
"key": "some.txt",
"AWSAccessKeyId": "ASI...",
"x-amz-security-token": "Ag9o...",
"policy": "eyJ...=",
"signature": "jn...="
as headers.
Are you using the fetch library?
Can you please post the JS code to?
I finally figure it out. This is the code.
formData = new FormData()
Object.keys(presignedPostData.fields).forEach(key => {
formData.append(key, presignedPostData.fields[key])
})
file = $('input[type="file"]')[0].files[0]
formData.append("file", file)
fetch(presignedPostData.url, {
method: 'POST',
body: formData,
mode: 'no-cors'
}).then((response) => {
lg('response', response)
})
Alright, found a ridiculously simple vanilla JS example that works!
$(document).ready(function () {
var PRESIGNED_URL = ""
$('input[type="file"]').change(function (e) {
var fileName = e.target.files[0].name;
var settings = {
"async": true,
"crossDomain": true,
"url": "https://my_api.com",
"method": "POST",
"headers": {
"Content-Type": "application/x-www-form-urlencoded",
},
"data": {
"filename": fileName
}
}
$.ajax(settings).done(function (response) {
$("#filename").html(fileName)
PRESIGNED_URL = response["url"]
$("#form").attr("action", response["url"])
$("#key").val(response["fields"]["key"])
$("#AWSAccessKeyId").val(response["fields"]["AWSAccessKeyId"])
$("#policy").val(response["fields"]["policy"])
$("#signature").val(response["fields"]["signature"])
$("#x-amz-security-token").val(response["fields"]["x-amz-security-token"])
return
});
});
$("#button").on("click", function (e) {
var form = document.getElementById('form');
var formData = new FormData(form);
var xhr = new XMLHttpRequest();
// Add any event handlers here...
xhr.upload.addEventListener('progress', function(e) {
var percent_complete = (e.loaded / e.total)*100;
// Percentage of upload completed
console.log(percent_complete);
});
xhr.onloadstart = function (e) {
console.log("start")
}
xhr.onloadend = function (e) {
console.log("end")
}
xhr.open('POST', PRESIGNED_URL, true);
xhr.send(formData);
$("#filename").html("")
})
});
There are so many close variations, but this on worked perfectly.
(I'm sure it seems obvious to many, but I only do front-end dev by necessity...)
Introduction
So I have an API that will upload a file to Azure with the following signature:
public async Task<IActionResult> Post([FromForm]IEnumerable<IFormFile> files)
This API was built and tested with Postman and it works great with the following parameters:
But when I attempt to call it within my react app with either the AJAX jQuery generated by Postman or axios, the IFormFile file variable is null.
handleFileChange = async (event) => {
let formData = new FormData();
let files = event.target.files[0];
formData.append('file', logo); // Can put "files" here or the imported picture "logo"
console.log("Form Data:", formData.get("files"));
await axios.post('api/files/uploadfiles', formData,{
'content-type': "multipart/form-data",
'Content-Type': "multipart/form-data",
})
.then(response => response.data)
.then(data => console.log("File Upload Response:" , data));
}
API Request that .NET Core gets with axios/ajax
API Request that .NET Core gets with Postman
You will notice here that the main difference is that the Postman has the file under files, while the axios request seems to only reference it under "Results View" but has nothing under files. Am I appending the correct item to the form? I have tried this with an imported image as well as a dynamic one from the following input field:
<FormGroup id = 'file-form'>
<Label for="file">Attach Files:</Label>
<Input type="file" name="files" id="File" onChange={this.handleFileChange}/>
</FormGroup>
but had no luck. Any help would be extremely
appreciated!!
Update #1
After reviewing some Microsoft documentation I discovered a caveat in the Microsoft docs that says enctype of the form to "multipart/form-data". I attempted this to no avail.
This is how I did it in the action method:
[HttpPost]
public void Post([FromForm]ValueFile files)
{
//do logic
}
Then I create a ViewModel named ValueFile
public class ValueFile
{
public IEnumerable<IFormFile> Files { get; set; }
}
In my web client I used jquery ajax:
$('#fileTest').on('change',
function() {
var fd = new FormData();
fd.append('files', $('#fileTest')[0].files[0]);
$.ajax({
"async": true,
"crossDomain": true,
"url": "http://localhost:5000/api/values",
"method": "POST",
"processData": false,
"contentType": false,
"mimeType": "multipart/form-data",
"data": fd
}).done(function (response) {
console.log(response);
});
});
<form id='file-form'>
<Label for="file">Attach Files:</Label>
<Input type="file" name="files" id="fileTest" />
</form>
Hope this helps
I'm simply trying to pass a text input and a file to Java but without success.
The formData seems to be working because I read the formData elements and all seems to be there. I just can't pass it to Java.
HTTP Status 500 - Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Current request is not a multipart request
HTML
<form id="creationForm" method="get" enctype="multipart/form-data">
<input id="testName" class="form-control" name="testName">
<input type="file" name="fileUpload" id="fileUpload"/>
</form>
JavaScript
$(document).ready(function () {
var files = [];
$('#fileUpload').change(function (event) {
files = event.target.files;
});
$('#btnSubmit').click(function (e) {
e.preventDefault();
var formData = new FormData(document.getElementById('creationForm'));
console.log(files[0]);
$.ajax({
type: 'get',
url: '/upload/testCase',
data: formData,
enctype: 'multipart/form-data',
processData: false,
contentType: false,
success: function (result) {
},
error: function () {
}
});
});
});
Java
#RequestMapping(value = "/upload/testCase", method = RequestMethod.GET)
public #ResponseBody void uploadTestCase(#RequestParam("fileUpload") MultipartFile file ) {
//TestCases.upload(file);
System.out.println(file);
}
Spring XML included bean
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />
I guess you're using the wrong http-method. Try to use post instead of get? That might solve it.
Spring:
#RequestMapping(value = "/upload/testCase" , method = RequestMethod.POST)
JQuery:
$.ajax({
type: 'post',
...
...
)};
According to https://spring.io/guides/gs/uploading-files/, this is the way your form should be defined to upload a file:
HTML
<form id="creationForm" method="POST" enctype="multipart/form-data" action="/upload/testCase">
<input id="fileName" class="form-control" name="name">
<input id="fileUpload" type="file" name="fileUpload"/>
<button class="form-control">Submit</button>
</form>
Java
#PostMapping("/upload/testCase")
public void uploadTestCase(#RequestParam("fileUpload") MultipartFile file) {
System.out.println(file);
}
In theory, you shouldn't need Javascript code for that.
But maybe you don't want the form to directly post your data, do you?
I want to send my form(which will have file and name in it) using javascript to the server using http.post request but I am not able to fetch file in javascript. How will i do that i have file path. And i don't want to do this using input tag.
var Form = new FormData();
Form.append("file", file);//this file has to added using path of the file
$http.post(url, Form, {
transformRequest: angular.identity,
headers: { 'Content-Type': undefined }
})
.success(function(d) {
console.log("sucess" + d);
});