在節點js中獲取八位字節流而不是圖像

[英]Getting octet-stream instead of image in node js


In my front-end I use angular6 and I have this form where you can choose an image either by dropping a file in a div or clicking the div to open a file picker.

在我的前端,我使用angular6,我有這種形式,您可以通過在div中刪除文件或單擊div打開文件選擇器來選擇圖像。

The form is

形式是

<form [formGroup]="imageUpload" (ngSubmit)="imageUploadSubmitted($event.target)"  > 
  <div id="imageDrop" (click)='imageInput.click()' (drop)="drop($event)" (dragover)="allowDrop($event)" #imageDrop></div> 
  <input type="file"  (change)='imageChange($event)' #imageInput id="imageInput" name = 'imageInput'  accept=".png, .jpg, .jpeg, .gif" formControlName="imageInput"  required  > 
  <button type="submit" >Submit</button>  
</form>

This is the typescript

這是打字稿

  selectedFile:File=null;

  allowDrop(e) {
    e.preventDefault();
  }

  drop(e) {    
    e.preventDefault();  
    this.imageUpload.controls.imageInput.reset();  
    this.selectedFile = e.dataTransfer.files[0];
    let input = this.imageUpload.controls.imageInput as any;        
    input.value = e.dataTransfer.files[0];     
  }

  imageChange(e){            
    this.selectedFile = e.target.files[0];
  }

So, when dropping an image, get it from the event and put it in the file input. When the form is submitted, send the form data to a service for posting. The console.log shows a File object (__proto__ : File) whether you picked an image from the file picker, or dropped one in the div.

因此,在刪除圖像時,從事件中獲取它並將其放入文件輸入中。提交表單后,將表單數據發送到服務進行發布。 console.log顯示一個File對象(__ proto__:File),無論你是從文件選擇器中選擇一個圖像,還是在div中刪除一個。

  imageUploadSubmitted(form){
    console.log('imageInput value - ', this.imageUpload.controls.imageInput.value);           
    this.mapcmsService.uploadImage(form).subscribe((data) =>{
      if(data.success){   alert('all good'); }
      else{ alert('error');  }
    })
  }

The service grabs the form controls and builds a FormData object to send in node.

該服務獲取表單控件並構建一個FormData對象以在節點中發送。

  uploadImage(data){
    let formData = new FormData(data);
    let headers = new Headers();
    headers.append('Authorization',this.userToken);
    return this.http.post('http://localhost:3000/user/upload/image', formData  ,{headers:headers}  ).pipe(map(res => res.json()));  
  }

In node I use formidable to get the file and save it. This is for testing.

在節點I中,使用formidable獲取文件並保存。這是為了測試。

  var form = new formidable.IncomingForm();

  form.parse(req);
  form.on('file', function (name, file){
    console.log('file' , file);
  });

The problem is that if I have chose an image via the file picker, I get a file of type image/jpeg , a name a path and a size.

問題是,如果我通過文件選擇器選擇了一個圖像,我會得到一個類型為image / jpeg的文件,一個名稱為路徑和大小的文件。

If I chose an image by drag and drop, I get a file of type application/octet-stream. This has no name and no size.

如果我通過拖放選擇圖像,我會得到一個application / octet-stream類型的文件。這沒有名字,沒有大小。

I would like to get image/jpeg in both cases. I am confused, is this a node or angular issue? How can I fix this ?

我想在兩種情況下都獲得image / jpeg。我很困惑,這是節點還是角度問題?我怎樣才能解決這個問題 ?

Thanks

angular 6 , node 8.11.1, formidable 1.2.1

角度6,節點8.11.1,強大的1.2.1

1 个解决方案

#1


3  

The issue is that the assignment in the drop event does not actually set the value of the input because file inputs are not supported by Angular reactive forms. I am talking about this lines:

問題是drop事件中的賦值實際上並未設置輸入的值,因為Angular反應形式不支持文件輸入。我在說這句話:

let input = this.imageUpload.controls.imageInput as any;        
input.value = e.dataTransfer.files[0];

So when you drop in your case you are not actually sending the file to the server at all. That is why the data you get is wrong. Here are also links to two other stack overflow questions about reactive forms and file upload where there is more information regarding this issue.

因此,當你放棄你的情況時,你實際上並沒有將文件發送到服務器。這就是為什么你得到的數據是錯誤的。這里還有關於反應形式和文件上傳的另外兩個堆棧溢出問題的鏈接,其中有關於此問題的更多信息。

There are two possible solutions to workaround this issue. The first is that you get the ElementRef of the file input by using the ViewChild query. And then assign the files to the native html element directly. The good thing with this approach is that you will see the dropped file name also in the file input. The downside is that this might not work in all browsers. The official documentation on MDN says that it works in modern browsers but for me it did work in Chrome and not in Edge. Here is a sample of the code:

有兩種可能的解決方案可以解決此問題。第一個是使用ViewChild查詢獲取文件輸入的ElementRef。然后直接將文件分配給本機html元素。這種方法的好處是您將在文件輸入中看到刪除的文件名。缺點是這可能不適用於所有瀏覽器。關於MDN的官方文檔說它可以在現代瀏覽器中運行,但對我來說它確實可以在Chrome中運行而不是在Edge中運行。以下是代碼示例:

@ViewChild('imageInput') private imageInput: ElementRef;

public drop(e: DragEvent) {    
    e.preventDefault();
    this.imageUpload.controls.imageInput.reset();  
    this.selectedFile = e.dataTransfer.files[0];
    this.imageInput.nativeElement.files = e.dataTransfer.files;
  }

The other approach is that you build the FormData object yourself by adding the selected file yourself in code before sending it to the server. This should work anywhere without issues. Here is a sample code:

另一種方法是通過在將代碼發送到服務器之前在代碼中自己添加所選文件來自己構建FormData對象。這應該在任何地方都可以解決。這是一個示例代碼:

let formData = new FormData();
formData.append('imageInput', this.selectedFile);

I have created also a StackBlitz example where you can see all the code.

我還創建了一個StackBlitz示例,您可以在其中查看所有代碼。


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2018/09/24/72f4c3c39815176c70a5df4768194e22.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com