$_FILES empty when sending Image with POST - javascript

I want to do pretty simple thing. Send image via HTTP to my Php Backend. However the $_FILES array remains empty.
My FrontEnd is looking like this:
const formData = new FormData();
formData.append('image', this.newPhoto);
await fetch('http://localhost:8080/addArticle', {
method: 'POST',
headers: {
'Content-Type': 'multipart/form-data',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': '*',
},
body: formData,
})
.then((response) => console.log(response))
.catch((error) => console.log(error));
My Payload in Network Tab on Dev Tools is looking like this: First time sending Images, so not really sure whether it looks correctly.
And on server side just simply try to see this files now via
var_dump($_FILES);
https://i.stack.imgur.com/KrN63.png
What am i missing?
In HTML it looks like this. Iam usinng Vuetify libarry for Vue:
<v-file-input v-model="newPhoto" show-size accept="image/*" label="Photo"></v-file-input>
Console log of example photo:
i.stack.imgur.com/mpy9d.png

Related

How to send a POST request as form-data when FormData is unavailable? (Airtable scripts)

The Cloudinary API requires to send data using multipart/form-data, but I'm working in an environment where FormData is not available.
How could I do something as simple as this, then?
const formData = new FormData();
formData.append('file', assetUrl);
formData.append('upload_preset', CLOUDINARY_UNSIGNED_UPLOAD_PRESET);
formData.append('cloud_name', CLOUDINARY_CLOUD_NAME);
console.debug(`Uploading file (id: ${id}) to Cloudinary`, CLOUDINARY_UPLOAD_URL, formData);
const response = await fetch(CLOUDINARY_UPLOAD_URL, {
method: 'POST',
body: formData,
});
I tried different approaches, but it seems the Cloudinary API is really sensitive about it, and doesn't allow sending data in any other format other than multipart/form-data.
Cloudinary API supports not only multipart/form-data, but also JSON and application/x-www-form-urlencoded.
If you're sending a string as the value of the file parameter, such as a remote URL (in your case) or Base64, then you can use any of the above-mentioned Content-Types.
For example, you could try the following example which will successfully upload the image into a cloud (you'll want to replace <your-cloud>, <file-url> and <upload-preset> with your actual values):
fetch('https://api.cloudinary.com/v1_1/<your-cloud>/image/upload', {
method: 'POST',
headers:{
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
'file': '<file-url>',
'upload_preset': '<upload-preset>'
})
});
Note that the cloud_name is derived from the URL you're sending the data to therefore it should not be sent in your request body.

Sending a csv from front-end to backend using axios

I am trying to send a csv file from my front end in reactjs to my back end in nodejs using axios. This csv file is selected via a browse UI button and stored in state using react. After searching online this is my code for the HTTPS request:
let formmData = new FormData();
formData.append('file', this.state.selectedFile);
const {data : QueryResult} = await axios({
method: 'post',
url: "https://localhost:...",
formData,
});
Note: this.state.selectedFile contains an object which when logged on console is:
File {name: "MyFile.csv", lastModified: 1614958303483, …}
I also would like to say that this endpoint works fine when using Postman as seen below:
After printing the request in my back-end in the case this request from my frontend I see:
body: {}
I don't understand what I am doing wrong and this passes nothing to my back-end.
I also saw that this was an open issue with axios on GitHub in the past.
Can this be achieved now with axios or should i use another module? Any ideas?
You need to do:
await axios({
method: 'post',
url: "https://localhost:...",
data: formData
});
because when you write just "formData", it becomes : { formData: formData } as per (new ES2015 object shorthand property name).
You can also use:
await axios.post('your_url', formData)

Can't add a file to fetch POST request

I have a request that succeeds in postman, but just fails when I call it from my JS code. The requests are similar in the Chrome dev tools, and I suspect that I'm just not adding the file correctly. This is how the file is added in the postman:
This is my JS code:
let formData = new FormData();
formData.append('file', event.target.files[0]);
fetch('http://localhost:8080/file/upload', {
method: 'POST',
headers:{
'Content-Type': 'multipart/form-data',
'Authorization': 'Bearer ' + JWT
},
body:formData
}).then(response => console.log(response));
This code is executed when the file of an input (type='file') changes. When I console.log the event.target.files[0], I get:
Am I adding the file wrong?
'Content-Type': 'multipart/form-data',
multipart/form-data needs a parameter to describe the boundry marker.
fetch will generate an appropriate Content-Type header automatically, but you are overriding it and replacing it with a broken one.
Remove that line.

Sending FormData not working in React-Native

I tried to communicate with an API to send a picture from an Iphone. I send form data by using Postman (key: mainPicture, value 'the file I choosed') and it's working well.
The problem come when I try to do it in js: the API don't find the file in my request.
Here is my code:
const formData = new FormData();
formData.append('mainPicture', {
uri: mainPicture.uri,
type: 'image/jpg',
name: `${mainPicture.id}.jpg`,
});
// ...
// api come from apisauce package
api.post(API_RES_IMG, formData, { headers: { ['Content-Type']: 'multipart/form-data' } })
Server say: "Error: Multipart: Boundary not found"
Without the content-type the server receive:
{"_parts":{"0":{"0":"mainPicture","1":{"uri":"assets-library://asset/asset.JPG?id=DE830A54-2526-44CB-81FE-00786D152080&ext=JPG","type":"image/jpg","name":"1e23519b-2006-4676-b63c-624e8198e17b.jpg"}}}}
Too much struggle from a simple thing.
Couple of issues I see here:
1) When using the fetch API, we don't need to set the Content-Type header, as fetch will take care of that, plus it will also take care of filling in the boundaries. I am assuming that this is the same with apisauce, however I might be wrong.
2) type: 'image/jpg' is not a valid mime type. It should be type: 'image/jpeg'.
you should add the content type
'Content-Type': type === 'form' ? 'multipart/form-data' : 'application/json',

Change a jquery ajax POST request into a fetch api POST

I have some json data that I have been posting to an API using $.ajax but I would like to update this to use the fetch API. However I seem to have it setup the Fetch API request ends up returning a 403 so I must be missing something but I can't work it out.
Ajax request:
$.ajax({
type: 'POST',
url: url,
data: {
'title': data.title,
'body': data.body,
'csrfmiddlewaretoken': csrf_token,
'request_json': true
},
success: function (data) {
console.log(data)
}
});
Fetch attempt (one of many):
let payload = {
'title': data.title,
'body': data.body,
'csrfmiddlewaretoken': csrf_token,
'request_json': true
}
let request = new Request(url, {
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: JSON.stringify( payload )
});
fetch(request)
.then((response) => {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
})
.then((response) => response.json())
I have tried with various different headers, content encoding and sending the data as form data using:
let form_data = new FormData();
form_data.append( "json", JSON.stringify( payload ) );
let request = new Request(url, {
method: 'post',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: form_data
});
...
Any help would be great and if you need any more info let me know
Thanks
To port an existing jQuery.ajax request to fetch, you need to consider that jQuery always includes cookies for you, but fetch does not.
Quoting MDN (emphasis mine):
Note that the fetch specification differs from jQuery.ajax() in mainly two ways that bear keeping in mind:
- The Promise returned from fetch() won’t reject on HTTP error status [ ... ]
- By default, fetch won't send or receive any cookies from the server, resulting in unauthenticated requests if the site relies on maintaining a user session (to send cookies, the credentials header must be sent).
Edit: spec has changed since then, so this should no longer be a problem:
Since Aug 25, 2017. The spec changed the default credentials policy to same-origin. Firefox changed since 61.0b13.
So the following (returning to original answer) only applies to "older" browsers.
Thanks David Richmond from comments :)
So you get 403 (Forbidden) because your API likely relies on cookies for authentication/authorization (even in your case, where you send a csrfmiddlewaretoken, the server-side framework might still expect a cookie with that -- guessing Django?).
To fix this, add credentials: "same-origin" to your Request (*), like so:
let request = new Request(url, {
method: 'post',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
(*) Valid options for credentials are:
omit: Never send cookies. This is the default (and your problem).
same-origin: Only send cookies if the URL is on the same origin as the calling script.
include: Always send cookies, even for cross-origin calls.
You say:
'Content-Type': 'application/x-www-form-urlencoded'
and
body: JSON.stringify( payload )
JSON Encoding is not the same thing as WWW Form Encoding!
You also tried
form_data.append( "json", JSON.stringify( payload ) );
FormData objects are converted to Multipart MIME.
Multipart MIME is also not the same as WWW Form Encoded data.
JSON nested inside Multipart MIME even less so.
This question describes how to convert an object (payload) into a Form Encoded string.

Categories