Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/35.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 上传角度文件-显示在req.body中,而不是nodejs服务器的req.files中_Node.js_Angular_Typescript_Multer - Fatal编程技术网

Node.js 上传角度文件-显示在req.body中,而不是nodejs服务器的req.files中

Node.js 上传角度文件-显示在req.body中,而不是nodejs服务器的req.files中,node.js,angular,typescript,multer,Node.js,Angular,Typescript,Multer,在使用multer作为中间件的nodejsapi中,我可以在request.file属性中看到postman post文件请求,当然,这些请求会保存在我的服务器上。请求与内容类型表单数据一起发送。只要在我的控制器上点击Save,文件就已经上传了。文件的所有详细信息都在request.files属性中 在Angular中,附加的文件被添加到请求主体中,我的nodejs应用程序无法保存该文件,因为中间件无法看到它。imagedata以base64编码字符串的形式出现 我曾尝试将angular中的标题

在使用multer作为中间件的nodejsapi中,我可以在request.file属性中看到postman post文件请求,当然,这些请求会保存在我的服务器上。请求与内容类型表单数据一起发送。只要在我的控制器上点击Save,文件就已经上传了。文件的所有详细信息都在request.files属性中

在Angular中,附加的文件被添加到请求主体中,我的nodejs应用程序无法保存该文件,因为中间件无法看到它。imagedata以base64编码字符串的形式出现

我曾尝试将angular中的标题设置为multipart/form数据,但出现500错误“multipart:Boundary not found”

在Postman中,如果我删除表单数据并将其设置为“无”,它也将不起作用

角分量 角度服务 节点设置 照片路由器 要保存的控制器
导出默认类DfrPhotoController{
//TODO:链接到dfr
公共存储=异步(请求:请求,响应:响应):承诺

谢谢

//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);
    });
  }
//使用图像选择器(html和ts)添加了组件
//HTML
照片评论
保存照片
//TS
从“@angular/core”导入{Component,OnInit};
从'@angular/forms'导入{FormControl,Validators,FormGroup};
从'src/app/shared/shared.service'导入{SharedService};
@组成部分({
选择器:“应用程序dfr照片”,
templateUrl:'./dfr photo.component.html',
样式URL:['./dfr photo.component.scss'],
})
导出类DfrPhotoComponent实现OnInit{
表格:表格组;
共享服务:共享服务;
构造函数(sharedService:sharedService){
this.sharedService=sharedService;
}
恩戈尼尼特(){
this.form=new FormGroup({
_id:new FormControl(空{
更新:“模糊”,
}),
dfrId:newformcontrol(null{
更新:“模糊”,
验证器:[验证器。必需]
}),
光通信:新FormControl(空{
更新:“模糊”,
验证器:[验证器。必需]
}),
图像:新FormControl(空{
更新:“模糊”
})
});
}
图像文件:任何;
onImagePicked(图像数据:字符串|文件){
如果(图像数据的类型=='string'){
试一试{
/*this.imageFile=this.sharedService.base64toBlob(
imageData.replace('data:image/jpeg;base64',''),
“图像/jpeg”
);*/
this.imageFile=imageData;
}捕获(错误){
console.log('Err'+error);
返回;
}
}否则{
this.imageFile=imageData;
}
patchValue({image:imageData});
this.form.get('image').updateValueAndValidity();
}
savePhoto(){
console.log(“保存”);
log(this.form.value.image);
this.sharedService.uploadPhoto(this.form.value.image).subscribe(val=>{
控制台日志(val);
});
}
}
//图像选择器代码-JS
从“@angular/core”导入{Component,OnInit,ElementRef,EventEmitter,ViewChild,Output,Input};
从“@capactor/core”导入{Plugins,CameraResultType,CameraSource,capactor};
从“@angular/platform browser”导入{SafeResourceUrl,domsanizer};
从'@ionic/angular'导入{Platform};
@组成部分({
选择器:“应用程序照相机”,
templateUrl:'./camera.component.html',
样式URL:['./camera.component.scss'],
})
导出类CameraComponent实现OnInit{
@ViewChild('filePicker')filePickerRef:ElementRef;
@Output()imagePick=neweventemitter();
@Input()showPreview=false;
选择图像:字符串;
usePicker=false;
构造函数(私有sanitizer:DomSanitizer,私有平台:platform){}
图2:安全资源URL;
恩戈尼尼特(){
if(this.platform.is('desktop')){
this.usePicker=true;
}
}
onPickImage(){
如果(!capactor.isPluginAvailable('Camera')){
this.filePickerRef.nativeElement.click();
返回;
}
Plugins.Camera.getPhoto({
质量:50,
来源:CameraSource.Prompt,
对,,
宽度:300,
结果类型:CameraResultType.Base64
})
。然后(图像=>{
const image2:any=image;//修复对base64数据的访问
this.selectedImage=image2.base64数据;
this.imagePick.emit(image2.base64Data);
})
.catch(错误=>{
console.log('ERROR'+ERROR);
if(this.usePicker){
this.filePickerRef.nativeElement.click();
}
返回false;
});
}
onFileChosen(事件:事件){
const pickedFile=(event.target作为HTMLInputElement.files[0];
如果(!pickedFile){
返回;
}
const fr=new FileReader();
fr.onload=()=>{
const dataUrl=fr.result.toString();
this.selectedImage=dataUrl;
this.imagePick.emit(dataUrl);/(pickedFile);
};
fr.readAsDataURL(pickedFile);
}
}
//图像选择器代码-HTML
拍照
//Sidenote-直接从表单控件发送的示例(重命名为image)
onImagePicked(图像数据:字符串|文件){
如果(图像数据的类型=='string'){
试一试{
/*this.imageFile=this.sharedService.base64toBlob(
imageData.replace('data:image/jpeg;base64',''),
“图像/jpeg”
);*/
this.imageFile=imageData;
}捕获(错误){
console.log('Err'+error);
返回;
}
}否则{
this.imageFile=imageData;
}
patchValue({image:imageData});
this.form.get('image').updateValueAndValidity();
}
savePhoto(){
this.sharedService.uploadPhoto(this.form.value.image).subscribe(val=>{
控制台日志(val);
});
}

我可以推荐Multer的替代方案吗

请参见以下每周npm下载:

  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});
  }
 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
          });
    }

}
//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);
    });
  }
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)
    )

  }