i need to send data from server by this format :
{
"name":"kianoush",
"userName":"kia9372",
"email":"kiadr9372#gmail.com"
}
i try to do this work :
update(item:UserEditModel): Observable<any>{
const formData: FormData = new FormData();
for (const key in item) {
if (item.hasOwnProperty(key)) {
if (item[key] instanceof File) {
formData.append(key, item[key], item[key].name);
} else {
formData.append(key, item[key]);
}
}
}
return this.httpClient.post(this.appConfig.apiEndpoint+'User/UpdateUser',
formData, {
headers:this.headers,
reportProgress: true,
observe: 'events'
})
.pipe(map(response => response || {} as HttpEvent<any>));
}
but it send to server by this format :
------WebKitFormBoundaryhWmbFWpD25WdeB9n
Content-Disposition: form-data; name="firstName"
vbnvbnvb
------WebKitFormBoundaryhWmbFWpD25WdeB9n
Content-Disposition: form-data; name="lastName"
vbnvbnvn
------WebKitFormBoundaryhWmbFWpD25WdeB9n
Content-Disposition: form-data; name="userName"
vbnvbnvb
------WebKitFormBoundaryhWmbFWpD25WdeB9n
Content-Disposition: form-data; name="roleId"
but i want to send data from server by this format :
{
"name":"kianoush",
"userName":"kia9372",
"email":"kiadr9372#gmail.com"
}
now how can i solve this problem ???
because you have the formdata its format is deferent from JSON
And if you don't have a file in the request just convert the formdata
to JSON
Or in the backend use [FromForm] before the dto
Normally when I have some files that should go to the server
I am using this kind of solution you can do it like this
First:
slectedFile: File;
//imgUrl for showing it in the html tag
imgUrl = '../assets/img/profilepic.png';
Second:
form: FormGroup = this.fb.group({
//........
file: [null]
});
Third:
onFileSelect(file) {
if (file.target.files[0]) {
this.slectedFile = file.target.files[0] as File;
const reader = new FileReader();
reader.readAsDataURL(this.slectedFile);
reader.onload = (event: any) => {
this.imgUrl = event.target.result;
};
}
}
And Last:
which I assume your main problem is here
const data= new FormData();
if (this.slectedFile) {
data.append('file', this.slectedFile, this.slectedFile.name);
}
and I should mention that personally use this package for input
https://www.npmjs.com/package/ngx-material-file-input
and in the html side you just say :
<mat-form-field class="col-md-12 ml-10 ngxmatfileinput">
<ngx-mat-file-input
(change)="onFileSelect($event)"
formControlName="file"
accept="image/*">
</ngx-mat-file-input>
<img [src]="imgUrl" class="float-left icon-fileupload" />
</mat-form-field>
if you not send file use following code
update(item:UserEditModel): Observable<any>{
const _data ={
"name":"item.name",
"userName":"item.userName",
"email":"item.email"
}
return this.httpClient.post(this.appConfig.apiEndpoint+'User/UpdateUser',
_data)
.pipe(map(response => response || {} as HttpEvent<any>));
}
Related
I'm using react-image-picker to take pictures and get the URI but I'm having problems receiving images as an IFormFile in my API. When using the "Content-Type": "multipart/form-data" header my array is null. Without it the array is empty but the data is there as a key-value pair the value is of type object inside HttpContext.Request.Form.
I've tried using both axios and fetch. I've tried sending the object as a blob with the content-type specified as image/jpeg, I've tried stringifying the Asset object but my request doesn't show a content-type for the FormData no matter what.
I tried creating a quick Vue project and the request goes through to my API as a file there without any issues.
It seems like the difference comes down to whether the FormData has a content-type specified. on Vue, it looks like
------WebKitFormBoundaryQoBY2Xgnc8K2sTzQ
Content-Disposition: form-data; name="photos"; filename="2560px-Random_Turtle.jpg"
Content-Type: image/jpeg
while in react it looks like. It looks like it even ignores the filename that's set in the append.
------WebKitFormBoundaryQoBY2Xgnc8K2sTzQ
Content-Disposition: form-data; name="photos"
Is there any way to force the content-type in the FormData? Using Blob like this doesn't change the request in any way
data.append("photos", new Blob([JSON.stringify(photo)], {type: "image/jpeg"}), "2560px-Random_Turtle")
React Native (Not working)
export const TestWithPhotosAPI = async (photos: Asset[]) => {
let data = new FormData();
if (containerAndPhotos.photos) {
containerAndPhotos.photos.forEach((photo) => {
data.append("photos", photo as Blob, "2560px-Random_Turtle");
});
}
fetch("https://myapi/postpicture", {
method: "POST",
body: data,
});
};
Vue project (Works)
<script setup lang="ts">
import { ref } from 'vue'
const form = ref(null)
const files = ref<FormData>(new FormData)
const filesChange = (event ) => {
console.log(event.target.files);
Array.from(event.target.files).map((file, index) => {
console.log(file);
files.value.append("photos", file as Blob, event.target.files[index].name)
})
}
const upload = () => {
fetch(
'https://myapi/postpicture',
{
method: "POST",
body: files.value
}
);
}
</script>
<template>
<form ref="form" #submit.prevent="upload">
<input type="file" name="file" multiple #change="(event) => filesChange(event)" />
<input type="submit" />
</form>
</template>
API (Works with Vue)
[HttpPost]
public ActionResult SetAsDone([FromForm] ICollection<IFormFile> photos)
{
var httpRequest = HttpContext.Request.Form;
return Ok();
}
I have a FILES variable that looks like this:
I am trying to receive these files at my Laravel controller like so:
if(!empty($request->allFiles()))
...
var_dump($request->all()); # debug
I am posting to this endpoint using the fetch API like so:
let fd = new FormData();
fd.append('files[]', FILES)
fetch('{{ url()->to(route('gallery.upload')) }}', {
method: 'POST',
credentials: "same-origin",
headers: {
"X-CSRF-Token": '{{ csrf_token() }}'
},
body: fd,
})
In my response (network tab) I get:
array(1) { ["files"]=> array(1) { [0]=> string(15) "[object Object]" } }
I tried to JSON.Stringify(FILES) and got:
array(1) { ["files"]=> array(1) { [0]=> string(70) "{"blob:http://127.0.0.1:8000/502cbd0f-f2b7-4155-8475-d83e48bb9730":{}}" } }
Can anyone point me in the right direction to why the file is not posted? This is how the FILES is created.
const fileTempl = document.getElementById("file-template"),
imageTempl = document.getElementById("image-template"),
empty = document.getElementById("empty");
let FILES = {};
function addFile(target, file) {
const isImage = file.type.match("image.*"),
objectURL = URL.createObjectURL(file);
const clone = isImage
? imageTempl.content.cloneNode(true)
: fileTempl.content.cloneNode(true);
// Creates nice output of the file
clone.querySelector("h1").textContent = file.name;
clone.querySelector("li").id = objectURL;
clone.querySelector(".delete").dataset.target = objectURL;
clone.querySelector(".size").textContent = file.size > 1024
? file.size > 1048576
? Math.round(file.size / 1048576) + "mb"
: Math.round(file.size / 1024) + "kb"
: file.size + "b";
isImage &&
Object.assign(clone.querySelector("img"), {
src: objectURL,
alt: file.name
});
empty.classList.add("hidden");
target.prepend(clone);
FILES[objectURL] = file;
}
You need to append files to your FormData object, not a plain object.
i.e. given formData.append("key", value), the value needs to be a file object (it can also be a string). It can't be a plain object (like FILES in your example) as that will be converted to a string, which isn't useful:
const object = {};
console.log(object.toString());
Manually extracting the files from a file input and appending them one-by-one is overly complex though. Typically you would just use a form instead of appending to the FormData object:
<form action="example" method="POST" enctype="multipart/form-data">
<input type="file" name="files[]" multiple>
<button>Submit</button>
</form>
<script>
const form = document.querySelector('form');
form.addEventListener('submit', event => {
const data = new FormData(form);
fetch('url', {
method: 'POST',
body: new FormData(form);
});
});
</script>
i'm writing a upload page using filepond. The problem i'm facing is to get it to work like i want. I need to get the metadata from the input and post it with additional formdata
I can allready post the image and additional formdata. However I also want the metadata from the input. If I use onaddfile and log the metadata it works and shows additional="1"
<input type="file" id="img" name="img" data-file-metadata-additional="1">
pond=FilePond.create(document.querySelector('#img'),{
server: {
process: {
url: 'opbouw/model/post/addimg.php',
ondata: (formData) => {
// > POST META DATA
formData.append('userid', '2');
formData.append('usercom', '1');
return formData;
}
}
},
});
pond.onaddfile = (err, item) => {
console.log(item);
const metadata = item.getMetadata();
console.log(metadata);
}
So no clue how to post the metadata
If you're not going to write a custom server.process method then you're going to have to "remember" which metadata belongs to which file.
Something like this:
<input type="file" id="img" name="img" data-file-metadata-additional="1">
<script>
let pondMetadata;
const pond = FilePond.create(document.querySelector('#img'), {
server: {
process: {
url: 'opbouw/model/post/addimg.php',
ondata: (formData) => {
// add metadata
formData.append('usermeta', JSON.stringify(pondMetadata));
formData.append('userid', '2');
formData.append('usercom', '1');
return formData;
}
}
},
onaddfile: (err, item) => {
pondMetadata = item.getMetadata();
}
});
</script>
When I want to upload an image and send the other data using FormData. Axios seems to serialize the image. Therefore, when i upload the image using Axios, the image is inside the body's payload as a string. As a result, I'm unable to use Multer on the server side to retrieve the uploaded image from the request.
This is my Vue code:
export default () {
name: 'app',
data () {
image: ''
},
methods: {
onFileChange (e) {
var files = e.target.files || e.dataTransfer.files
if (!files.length) {
return
}
// console.log(files[0])
// var x = files[0]
return this.createImage(files[0])
// return new Buffer(x)
},
createImage (file) {
// var image = new Image()
var reader = new FileReader()
var vm = this
reader.onload = (e) => {
// vm.image = e.target.result
vm.image = file.toString('base64')
console.log(vm.image)
}
reader.readAsDataURL(file)
},
submitStaff () {
const formData = new FormData()
formData.append('file', this.image)
formData.append('name', this.data.name)
formData.append('username', this.data.username)
formData.append('password', this.data.password)
axios.post('api/myApiUrl', formData)
.then(function (response) {
console.log(response)
})
.catch(function (error) {
console.log(error)
})
}
}
<input type="file" #change="onFileChange">
Request Payload (Error with Vue)
Request Payload (Successful with Postman)
How do i fix this? Thank you!
I faced a problem related to it and in my case I was setting Content-Type as a default configuration for all my requests, doing this:
axios.defaults.headers.common['Content-Type'] = 'application/json [or something]';
And, as I remember, part of my solution was to remove this configuration to make the upload works. I just erased that line from my code and all requests worked well. As soon I removed it, I could notice that my headers request changed to this (see attached image and notice the Content-Type entry):
Another thing you should be alert is the field name to your <input type="file" name="file">. I have a java backend expecting a parameter named as "file", so, in my case, my input file HAS to be set as "file" on my HTML and on my server side, like this:
public ResponseEntity<Show> create(
#RequestParam("file") MultipartFile file,
RedirectAttributes redirectAttributes) { ... }
Observe the entry #RequestParam("file")...
And in the HTML file:
<form enctype="multipart/form-data" novalidate v-if="isInitial || isSaving">
<div class="well">
<div class="form-group">
<label>* Selecione o arquivo excel. O sistema fará o upload automaticamente!</label>
<div class="dropbox">
<input type="file" single name="file" :disabled="isSaving" #change="filesChange($event.target.name, $event.target.files); fileCount = $event.target.files.length"
accept="application/vnd.ms-excel" class="input-file">
<p v-if="isInitial">
Solte o arquivo excel aqui<br> ou clique para buscar.
</p>
<p v-if="isSaving">
Carregando arquivo...
</p>
</div>
</div>
</div>
</form>
You also can take a look at this tutorial, it my help you: https://scotch.io/tutorials/how-to-handle-file-uploads-in-vue-2
I hope it helps you!
I have an image (base64) that I need to send via a POST request (and wait for the response). The POST request needs to be of Content-Type:multipart/form-data.
The image needs to be of Content-Type: image/jpg
The POST request should look like:
POST https://www.url... HTTP/1.1
Content-Type: multipart/form-data; boundary=-------------------------acebdf13572468
User-Agent: Fiddler
Host: www.host.com
Content-Length: 199640
---------------------------acebdf13572468
Content-Disposition: form-data; name="fieldNameHere"; filename="Nikon Digital SLR Camera D3100 14.2MP 2.jpg"
Content-Type: image/jpeg
With the binary image data as the content body.
I'm attempting to use the Http Post method of angular 2, but I'm not quite sure about how to generate the request.
This is what I have:
let body = atob(imageData);
let headers = new Headers({'Content-Type': 'multipart/form-data'});
let options = new RequestOptions({headers: headers});
this._http.post(url, body, options)
.map(res=>{
//do stuff
});
I can tell that I am missing part of it but I am not sure what I need to do to give the binary image data it's Content-Disposition & Type etc.
Form template
<form id="form" name="file" [formGroup]="FileFormGroup"(submit)="addFrom($event, FileFormGroup)" method="post">
<input spellcheck="true" formControlName="Demo" name="Demo" type="text"/>
<input type="file" accept="image/*" id="file" name="File"/>
<input formControlName="File" type="hidden"/>
</form>
Ts
import {FormGroup, FormBuilder, FormControl, Validators} from '#angular/forms';
import {ValidatorFn} from '#angular/forms/src/directives/validators';
public FileFormGroup: FormGroup; /* variable */
constructor(public fb: FormBuilder) {}
ngOnInit() {
this.FileFormGroup = this.fb.group({
Demo: ["", Validators.required],
File: ["", this.fileExtension({msg: 'Please upload valid Image'})]
});
}
public addFrom(event: Event, form: FormGroup): void {
if(form.valid && form.dirty) {
let formTemp: HTMLFormElement <HTMLFormElement>document.querySelector('#form');
let formData: FormData = new FormData(formTemp);
let xhr: XMLHttpRequest = this.foo(formData);
xhr.onreadystatechange = () => {
if(xhr.readyState === 4) {
if(xhr.status === 201) {
console.log("Success");
} else {
console.log("Error");
}
}
}
}}
// Foo function
public Foo(formData){
let url: Foo;
let xhr: XMLHttpRequest = new XMLHttpRequest();
xhr.open('POST', url, true);
// enctype For Multipart Request
xhr.setRequestHeader("enctype", "multipart/form-data");
// IE bug fixes to clear cache
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader("Cache-Control", "no-store");
xhr.setRequestHeader("Pragma", "no-cache");
xhr.send(formData);
return xhr;
}
/* validation function to check proper file extension */
public fileExtension(config: any): ValidatorFn {
return (control: FormControl) => {
let urlRegEx: RegExp = /\.(jpe?g|png|gif)$/i;
if(control.value && !control.value.match(urlRegEx)) {
this.deleteImg = false;
return {
invalidUrl: config.msg
};
} else {
return null;
}
};
}
Similar to this question here: Angular 2 - Post File to Web API
Angular2 does not yet support multipart/form-data POST requests, so I decided to use jQuery instead to implement it, and then convert it to an RxJs Observable (subject) to have the same type as what the http.post function in Angular2 should have:
//Convert Base64 Representation of jpeg to
let imageData = imageString.split(',')[1];
let dataType = imageString.split('.')[0].split(';')[0].split(':')[1];
let binaryImageData = atob(imageData);
let data = new FormData();
let blob = new Blob([binaryImageData], { type: dataType })
data.append('file', blob);
let deferred = $.ajax({
url: this._imageAPIBaseUrl,
data: data,
cache: false,
contentType: false,
processData: false,
type: 'POST'
});
let observable = new AsyncSubject();
//When the Deferred is complete, push an item through the Observable
deferred.done(function () {
//Get the arguments as an array
let args = Array.prototype.slice.call(arguments);
//Call the observable next with the same parameters
observable.next.apply(observable, args);
//Complete the Observable to indicate that there are no more items.
observable.complete();
});
//If the Deferred errors, push an error through the Observable
deferred.fail(function () {
//Get the arguments as an array
let args = Array.prototype.slice.call(arguments);
//Call the observable error with the args array
observable.error.apply(observable, args);
observable.complete();
});
return observable;
Please check this working example (not mine): https://plnkr.co/edit/ViTp47ecIN9kiBw23VfL?p=preview
1 - Don't change or set the Content-Type
2 - Use FormData to send parameters
3 - Add this to app.module.ts:
import { HttpModule, RequestOptions, XHRBackend, ConnectionBackend, Http, Request, RequestOptionsArgs, Response, Headers } from '#angular/http';
#Injectable()
export class HttpInterceptor extends Http {
constructor(backend: ConnectionBackend, defaultOptions: RequestOptions)
{
super(backend, defaultOptions);
defaultOptions.headers = new Headers();
defaultOptions.headers.append('Content-Type', 'application/json');
}
}