How to angular2 post JSON data and files In same r

2020-01-29 08:04发布

问题:

I want to implement post file and Json data in the same request .

below is the upload file code :

upload(url:string,file:File):Observable<{complate:number,progress?:number,data?:Object}>{


    return Observable.create(observer => {
      const formData:FormData = new FormData(),
        xhr:XMLHttpRequest = new XMLHttpRequest();
      formData.append('uploadfile', file);


      formData.append("_csrf", this.tokenService.getCsrf());
      xhr.open('POST',url, true);
      xhr.onreadystatechange = () => {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            observer.next({complate:1,progress:100,data:JSON.parse(xhr.response)});
            observer.complete();
          } else {
            observer.error(xhr.response);
          }
        }
      };

      xhr.upload.onprogress = (event) => {
        observer.next({complate:0,progress:Math.round(event.loaded / event.total * 100)});
      };


      const headers=new Headers();
      let token: string = localStorage.getItem('access-token');
      xhr.setRequestHeader('Authorization', `Bearer ${token}`);
      xhr.send(formData);
    }).share();

How to integration with angular2 http.post(url, JSON.stringify(data)).

回答1:

So I've been trying to do that too, and for something which look really simple I ended up with a lot of trouble to figure out a solution. Hopefully some coworkers helped me and we came up with something reasonable.

This documentation helped us a lot: https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects

And here's the Angular code:

class SomeService {
  someMethod(fileToUpload: File, name: string, version: string) {
    const formData: FormData = new FormData();
    formData.append('file', fileToUpload, fileToUpload.name);

    const overrides = {
      name,
      version,
    };

    const blobOverrides = new Blob([JSON.stringify(overrides)], {
      type: 'application/json',
    });

    formData.append('overrides', blobOverrides);

    const req = new HttpRequest('POST', `some-url`, formData);

    return this.http.request(req);
  }
}

As @Supamiu said, using Blob was the key, and here's an example how to do that.



回答2:

//app.component.html

<input type="file" name="file" (change)="onChange($event)">
<button (click)="onSubmisson()" [disabled]="file==null" >Submit</button>

//app.component.ts

file:File = null;

onChange(event){
 this.file = event.target.files[0]
}

onSubmisson(){
 this._auth.uploadFileAndData(this.file).subscribe(
 res => {
    console.log(res);
 },err => {
    console.log(err);
 });
}

//upload.service.ts

uploadFileAndData(file){
  var test = {test:"test"}
  const formData = new FormData();
  formData.append('data', JSON.stringify(test));
  formData.append('file', file, file.name);
  return this._http.post<any>(this._uploadurl, formData);
}

//node server

var multer = require('multer');
var path = require('path');

var storage = multer.diskStorage({
  // destination
  destination: function (req, file, cb) {
    cb(null, './uploads/')
  },
  filename: function (req, file, cb) {
    cb(null, file.originalname);
  }
});

var upload = multer({ storage: storage }).array("file", 12);

router.post("/upload",  function(req , res){
    upload(req, res, function (err) {
        if(err){
            console.log(err);
        }else{
            console.log(req.body);
            console.log('files', req.files);
        }
    })
    res.status(200).send({});
});

// output

{ data: '{"test":"test"}' }

files [ { fieldname: 'file',
    originalname: 'acfcdea5-28d2-4f2e-a897-1aef3507193d.jpg',
    encoding: '7bit',
    mimetype: 'image/jpeg',
    destination: './uploads/',
    filename: 'acfcdea5-28d2-4f2e-a897-1aef3507193d.jpg',
    path: 'uploads\\acfcdea5-28d2-4f2e-a897-1aef3507193d.jpg',
    size: 49647 } ]


回答3:

The below client and service code works fine in my solution, check if this helps

Client Side Code:

    AddModelData(modelData: ModelData, file: any): Observable<any> 
    {
      let urlPath = 'api/SampleActionMethod/AddModelData';
      const mData = JSON.stringify(modelData);
      const formData = new FormData();
      formData.append('data', mData);
      if (file) {
        formData.append('file', file, file.name);
      }
      return this._http.post(this.settings.apiEndPoint + urlPath, formData);
    }

Service Side Code:

public IActionResult PostMethod(IFormFile file)
{      
  try
  {                
    var modelData = JsonConvert.DeserializeObject<ModelData>(Request.Form["data"]); 
    //data is the key that is being passed from client side
    //file in params will have the posted file

    //Do Something with data and file......

    return Ok();
  }
  catch (Exception e)
  {
    return StatusCode(500, e.Message);
  }
}


回答4:

The way my manager @Jesse come up with is like:

public uploadFiles(id: ServerID, brd: File, sch: File, args: any[]): Observable<Blob> {
        const data = new FormData();
        data.append('brd', brd);
        data.append('sch', sch);
        data.append('data', JSON.stringify(args));
        return this.httpClient.post(URL, data, {
            responseType: 'blob',
        });
    }

The definition of the FormData append() is append(name: string, value: string | Blob, fileName?: string): void; which allows you to append JSON parameters to it or upload a file.