Загрузка файла в формате Angular - отображается в файле req.body вместо файла req.files для сервера nodejs - PullRequest
1 голос
/ 01 мая 2019

В моем nodejs api, использующем multer в качестве промежуточного программного обеспечения, я вижу запросы файла почты почтальона в свойстве request.file, которое, конечно, затем сохраняется на моем сервере.Запрос отправляется с типом контента form-data.Как только на моем контроллере нажата кнопка «Сохранить», файл уже загружен.Все детали файла (ов) находятся в свойстве request.files

. В Angular прикрепленный файл добавляется в тело запроса, и мое приложение nodejs не может сохранить файл, так как промежуточное ПО не видитЭто.Imagedata приходит как строка в кодировке base64

Я попытался установить заголовки в угловых для multipart / form-data, но я получаю ошибку 500 "Multipart: Граница не найдена".

В Почтальоне, если я удаляю данные формы и задаю значение «Нет», он также не работает

Угловой компонент

  imageFile:any;

  onImagePicked(imageData: string | File) {
    if (typeof imageData === 'string') {
      try {
        /*this.imageFile = this.sharedService.base64toBlob(
          imageData.replace('data:image/jpeg;base64,', ''),
          'image/jpeg'
        );*/
        this.imageFile = imageData;
      } catch (error) {
        console.log('Err' + error);
        return;
      }
    } else {
      this.imageFile = imageData;
    }
  }

  savePhoto() {
    console.log ('Save');
    this.sharedService.uploadPhoto(this.imageFile).subscribe(val => {
      console.log(val);
    });
  }

Служба углов

  public uploadPhoto(image: File) {
      //let headers = new HttpHeaders();
      //headers = headers.append('Content-Type', 'multipart/form-data');
      const imageData = new FormData();
      imageData.append('image', image);
      return this.httpClient.post(environment.apiURL + this.path, imageData);
      //return this.httpClient.post(environment.apiURL + this.path, imageData, {headers: headers});
  }

Nodejs Setup

 public express: express.Application;

  constructor() {
    this.express = express();

    this.setMiddlewares();
    this.setRoutes();
    this.catchErrors();
    this.setSocketServer();
  }

  private setMiddlewares(): void {
    this.express.options('*', cors());
    this.express.use(cors());
    this.express.use((reg, res, next) => {
      res.setHeader('Access-Control-Allow-Origin', '*');
      res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, POST, PUT, PATCH, DELETE');
      res.setHeader('Access-Control-Allow-Headers', '*');
      res.setHeader('Access-Control-Max-Age', 10000);
      next();
    });
    this.express.use(morgan('dev'));
    this.express.use(bodyParser.json());
    this.express.use(bodyParser.urlencoded({ extended: false }));
    this.express.use(helmet());

    const storageConfig = multer.diskStorage({
      destination: (req, file, callback) => callback(null, './files'),
      filename: (req, file, callback) => callback(null, Date.now() + "-"  + file.originalname),
    });
    this.express.use(multer({storage: storageConfig}).any());

  }

  private setRoutes(): void {
    this.express.use('/api', api);
  }

Маршрутизатор для фотографий

import { Router } from "express";
import DfrPhotoController from "./dfrphoto.controller";

const dfrPhoto: Router = Router();
const controller = new DfrPhotoController();


dfrPhoto.post('/', controller.save);

export default dfrPhoto;

Контроллер для сохранения

export default class DfrPhotoController {

    // TODO: link to the dfr
    public save = async (req:Request, res:Response): Promise<any> => {

        // Need to see files in request. File is already saved in 
        let files = req.files; 
        console.log (files);
        if (files === null || files === undefined ) {
            res.status(404).send({
                success: false,
                message:'No Files Found'
              });
        }

        console.log("The file was saved!");
        res.status(200).send({
            success: true,
            message:'Photo saved',
            data: files
          });
    }

}

Я бы хотел, чтобы угловая загрузка файла работала точно так жекстати как пример почтальона.Я не против записи файла, как только я вызову команду save в контроллере, поскольку я могу добавить проверку в промежуточное ПО.Если у кого-то есть идеи по этому поводу, я был бы признателен

Образец угловой отправки запроса enter image description here

Спасибо

//Added Component using the image picker (html and ts)
//HTML
  <ion-grid>
    <form [formGroup]="form" >  
        <ion-row size="12">
            <ion-col  size-lg="6" size-xl="6" size="12"   size-md="12">
                <app-camera  (imagePick)="onImagePicked($event)"></app-camera>
                <!-- <ion-thumbnail>
                  <ion-img  width="200" height="200"  [src]="imageFile" ></ion-img>

                </ion-thumbnail>-->
                <img  [src]="imageFile"  >
            </ion-col>
            <ion-col  size-lg="6" size-xl="6" size="12"   size-md="12">
                <ion-label  position="floating">Photo Comments</ion-label>
                <!-- <ion-textarea rows="3" formControlName="rigComments"></ion-textarea>-->
                <ion-textarea rows="3" formControlName="photoComments"></ion-textarea>
            </ion-col>
        </ion-row>
        <ion-row>
            <ion-button (click)="savePhoto()">Save Photo</ion-button>
        </ion-row>
    </form>  
  </ion-grid>

//TS
import { Component, OnInit } from '@angular/core';
import { FormControl, Validators, FormGroup } from '@angular/forms';
import { SharedService } from 'src/app/shared/shared.service';

@Component({
  selector: 'app-dfr-photo',
  templateUrl: './dfr-photo.component.html',
  styleUrls: ['./dfr-photo.component.scss'],
})
export class DfrPhotoComponent implements OnInit {

  form: FormGroup;
  sharedService: SharedService;

  constructor(sharedService: SharedService) {
      this.sharedService = sharedService;
   }

  ngOnInit() {
    this.form = new FormGroup({
      _id: new FormControl(null, {
        updateOn: 'blur',
      }),
      dfrId: new FormControl(null, {
        updateOn: 'blur',
        validators: [Validators.required]
      }),
      photoComments: new FormControl(null, {
        updateOn: 'blur',
        validators: [Validators.required]
      }),
      image: new FormControl(null, {
        updateOn: 'blur'
      })
    });
  }

  imageFile:any;

  onImagePicked(imageData: string | File) {
    if (typeof imageData === 'string') {
      try {
        /*this.imageFile = this.sharedService.base64toBlob(
          imageData.replace('data:image/jpeg;base64,', ''),
          'image/jpeg'
        );*/
        this.imageFile = imageData;
      } catch (error) {
        console.log('Err' + error);
        return;
      }
    } else {
      this.imageFile = imageData;
    }
    this.form.patchValue({ image: imageData });
    this.form.get('image').updateValueAndValidity();
  }

  savePhoto() {
    console.log ('Save');
    console.log(this.form.value.image);
    this.sharedService.uploadPhoto(this.form.value.image).subscribe(val => {
      console.log(val);
    });
  }

}


// Image Picker Code - JS
import { Component, OnInit, ElementRef, EventEmitter, ViewChild, Output, Input } from '@angular/core';
import { Plugins, CameraResultType, CameraSource, Capacitor} from '@capacitor/core';
import { SafeResourceUrl, DomSanitizer } from '@angular/platform-browser';
import { Platform } from '@ionic/angular';


@Component({
  selector: 'app-camera',
  templateUrl: './camera.component.html',
  styleUrls: ['./camera.component.scss'],
})
export class CameraComponent implements OnInit {

  @ViewChild('filePicker') filePickerRef: ElementRef<HTMLInputElement>;
  @Output() imagePick = new EventEmitter<string | File>();
  @Input() showPreview = false;
  selectedImage: string;
  usePicker = false;


  constructor( private sanitizer: DomSanitizer, private platform: Platform) { }

  image2: SafeResourceUrl;

  ngOnInit() {
    if ( this.platform.is('desktop')) {
      this.usePicker = true;
    }
  }

  onPickImage() {
    if (!Capacitor.isPluginAvailable('Camera')) {
      this.filePickerRef.nativeElement.click();
      return;
    }
    Plugins.Camera.getPhoto({
      quality: 50,
      source: CameraSource.Prompt,
      correctOrientation: true,
      width: 300,
      resultType: CameraResultType.Base64
    })
      .then(image => {
        const image2: any = image; // to fix access to base64 data
        this.selectedImage = image2.base64Data;
        this.imagePick.emit(image2.base64Data);

      })
      .catch(error => {
        console.log('ERROR ' + error);
        if (this.usePicker) {
          this.filePickerRef.nativeElement.click();
        }
        return false;
      });
  }

  onFileChosen(event: Event) {
    const pickedFile = (event.target as HTMLInputElement).files[0];
    if (!pickedFile) {
      return;
    }
    const fr = new FileReader();
    fr.onload = () => {
      const dataUrl = fr.result.toString();
      this.selectedImage = dataUrl;
      this.imagePick.emit(dataUrl);// (pickedFile);
    };
    fr.readAsDataURL(pickedFile);
  }

}



// Image Picker Code - HTML
  <div class="picker">

    <ion-button color="primary" (click)="onPickImage()" *ngIf="!usePicker">
      <ion-icon name="camera" slot="start"></ion-icon>
      <ion-label>Take Picture</ion-label>
    </ion-button>
  </div>
  <input
    type="file"
    accept="image/jpeg"
    *ngIf="usePicker"
    #filePicker
    (change)="onFileChosen($event)"
  />




// Sidenote - Example of sending directly from the form control (renamed to image)
onImagePicked(imageData: string | File) {
    if (typeof imageData === 'string') {
      try {
        /*this.imageFile = this.sharedService.base64toBlob(
          imageData.replace('data:image/jpeg;base64,', ''),
          'image/jpeg'
        );*/
        this.imageFile = imageData;
      } catch (error) {
        console.log('Err' + error);
        return;
      }
    } else {
      this.imageFile = imageData;
    }
    this.form.patchValue({ image: imageData });
    this.form.get('image').updateValueAndValidity();
  }

  savePhoto() {
    this.sharedService.uploadPhoto(this.form.value.image).subscribe(val => {
      console.log(val);
    });
  }

1 Ответ

1 голос
/ 01 мая 2019

Могу ли я предложить альтернативу Малтеру?

См. Ниже еженедельные загрузки npm:

Multer: 466 964

грозно: 2116997

сервер nodejs:

app.post('/upload', (req, res) => {

    var form = new formidable.IncomingForm()
    form.parse(req)

    form.on('fileBegin', function (name, file) {
        var path = __dirname + '/uploads'
        if (!fs.existsSync(path)) {
            fs.mkdirSync(path)
        }
        file.path = __dirname + '/uploads/' + file.name;
    });

    form.on('file', function (name, file) {
        console.log('Uploaded ' + file.name);
        res.send({ message: 'uploaded' })
    });
})

угловой шаблон:

<input type="file" (change)="onFileInput($event)" placeholder="Upload file" accept=".JPG,.pdf,.doc,.docx">

угловой компонент:

onFileInput(event) {
    let fileList: FileList = event.target.files;
    let file = fileList[0]
    console.log(file);
    let formData: FormData = new FormData();
    formData.append('uploadFile', file, file.name);
    this.http.post('http://localhost:3001/upload', formData).subscribe(
      res => console.log(res)
    )

  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...