How to upload a file along with form data using http.post

I am submitting a form with fields like title and description using http.post and it works fine. I also allow user to use the camera to capture a photo and save it as a string in base64 format. I need to submit this photo to the server via the same POST request. How can I do this? My code so far is as the following and the server looks for the uploaded photo in a field named “photo”:

headers = new Headers({'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8'});
options = new RequestOptions({ headers: this.headers });

let data = {
  title: item.title,
  description: item.description
};

let params = new URLSearchParams();
for(let key in data){
    params.set(key, data[key]) 
}

this.http.post('http://example.com/items', params.toString(), this.options).subscribe(
  (result) => {
    console.log("success!");
  },
  (err) => {
    console.log(JSON.stringify(err));
  }
);
1 Like

Anonymous sorry for post it

And how to include the photo in the POST request after doing that?

</> please ref following code.

this.signature = this.signaturePad.toDataURL();

sessionStorage.setItem("Signature", this.signature);

this.Base64Signature = this.signature.replace(/^data:image\/(png|jpg);base64,/, "");

var i = JSON.stringify({
    Id: this.localId, DeliverymanId: this.localDeliverymanId, Image: this.Base64Signature , Qty: this.qty, Remarks: this.remarks, Status: this.Status,
    Photo: this.Photo64, Reason: this.localReasonId, BusinessUnitId: this.BussinessUnitId, CreatedUserId:  this.UserId, ModifiedUserId: this.UserId
  });

None of this is ever necessary, and is in fact counterproductive, introduces opportunities for bugs, and makes code needlessly verbose and hard to read. Simply pass an object as the body payload and the content type will be set appropriately by Angular.

Ok I changed my code to this:

let data = {
  title: item.title,
  description: item.description,
  photo: item.photo
};

this.http.post('http://example.com/items', data).subscribe(
  (result) => {
    console.log("success!");
  },
  (err) => {
    console.log(JSON.stringify(err));
  }
);

item.photo is set this way:

const options: CameraOptions = {
  quality: 100,
  targetWidth: 800,
  sourceType: this.camera.PictureSourceType.CAMERA,
  destinationType: this.camera.DestinationType.DATA_URL,
  encodingType: this.camera.EncodingType.JPEG,
  mediaType: this.camera.MediaType.PICTURE
}
this.camera.getPicture(options).then((imageData) => {
  this.photo = 'data:image/jpeg;base64,' + imageData;
}, (err) => {
  console.log("error occured!");
});

The above code only submit the title and description fields though. No field named “photo” becomes available on the server side. The photo is captured correctly and I can show it in my app before submitting.

@Arulmano could you please elaborate on the sample code you have provided?

Are we certain that photo is set at the time we are attempting to post it?

Here is the first think, the Photo string data is too long so send your data with JSON.stringify and getting that data as JSON(your Backend) and serialization it.

Yes, I logged it before calling http.post and it’s a long string starting with data:image/jpeg;base64. Is this how a file should be uploaded by POST request?

I suspect your problem is that you’re overflowing the URL length. www-form-encoded puts everything in the query string. I think you are going to need whoever is in charge of the backend to switch to accepting JSON instead.

I changed the backend to accept JSON. What should I do now?

It’s really strange that there is no straight forward answer to this question. Am I the first one in the world of ionic who is trying to submit a file along with form data to server? :confused:

Get rid of all the headers and requestoptions and URLSearchParams junk and just put the data URL in the data object and pass data itself as the payload to http.post(). Angular will set the content type to application/json for you.

I already did that. Look at my 3rd post in this thread. After that change, “photo” was not received in the backend.

I can’t tell what is going where because item and data are so vague, but the only place that you can rely on that photo is inside the then block, so you have to do all your posting from in there.

I log data.photo before calling http.post and it’s always a long string starting with data:image/jpeg;base64. So rest assured that photo is not empty. Besides, in my application http.post is never called immediately after the photo is taken, so there is no need to POST data in then.

You can use the Network tab of Chrome’s developer tools to see what is going over the wire. That will tell you whether the problem is on the Ionic side or the server side. Server logs may also be relevant.

Ok I will do that. Also let me point out that I could upload the file and form data using File Transfer Plugin. The problem with file transfer plugin though is that it can only post one file at each request (It is actually equivalent to submitting a form which contains only one file).

@rapropos This is what is logged in the Network tab:

Request URL:http://192.168.1.102/items
Request Method:POST
Status Code:201 Created
Request Headers
Accept:application/json, text/plain, /
content-type:application/json
Origin:http://192.168.1.102:8100
Referer:http://192.168.1.102:8100/
User-Agent:Mozilla/5.0 (Linux; Android 4.4.2; LG-D802 Build/KOT49I.D80220c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Mobile Safari/537.36
Request Payload
{title:some-title, description:some-desc,…}
description: “some-desc”
photo: “data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBA…” => (very long string)
title: “some-title”
Response Headers
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:http://192.168.1.102:8100
Access-Control-Expose-Headers:*
Cache-Control:no-cache
Connection:Keep-Alive
Content-Length:0
Content-Type:text/html; charset=UTF-8
Date:Wed, 27 Sep 2017 21:07:25 GMT
Keep-Alive:timeout=5, max=100
Server:Apache/2.4.23 (Win64) PHP/5.6.25
Vary:Origin
X-Powered-By:PHP/5.6.25

That would seem to indicate that the Ionic side is doing its job, so I would shift to looking at blaming the server side.

What if I told you I posted the same parameters (title, description, photo) to the same URL using postman and it was successful? I also posted the same parameters using ionic’s File Transfer plugin and it was successful too. So there is no doubt that the server side should not be blamed for this problem.