【问题标题】:Getting octet-stream instead of image in node js在节点 js 中获取八位字节流而不是图像
【发布时间】:2018-09-30 19:41:51
【问题描述】:

在我的前端中,我使用 angular6,我有这个表单,您可以通过将文件放入 div 或单击 div 打开文件选择器来选择图像。

表格是

<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>

这是打字稿

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

因此,当删除图像时,从事件中获取它并将其放入文件输入中。提交表单后,将表单数据发送到服务以进行发布。 console.log 显示一个文件对象 (__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');  }
    })
  }

该服务抓取表单控件并构建一个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()));  
  }

在节点中,我使用强大的来获取文件并保存它。这是为了测试。

  var form = new formidable.IncomingForm();

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

问题是,如果我通过文件选择器选择了一个图像,我会得到一个 image/jpeg 类型的文件、一个名称、一个路径和一个大小。

如果我通过拖放选择图像,我会得到一个application/octet-stream 类型的文件。这个文件没有名称,也没有大小。

我想在这两种情况下都得到image/jpeg我很困惑,这是节点问题还是角度问题?我怎样才能解决这个问题 ?

谢谢

棱角6,节点8.11.1,强大1.2.1

【问题讨论】:

  • 你能在像 Codepen 这样的代码操场上隔离这个(仅限客户端部分)吗? codepen.io/anon/pen/zJgVea(这是一个角模板)
  • (drop)="drop($event)" 功能的动力是什么?什么代码实现了drop 指令?

标签: node.js angular file-upload formidable


【解决方案1】:

问题在于 drop 事件中的赋值实际上并没有设置输入的值,因为 Angular 响应式表单不支持文件输入。我说的是这几行:

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

因此,当您放入您的案例时,您实际上根本没有将文件发送到服务器。这就是为什么你得到的数据是错误的。这里还有另外两个关于反应式表单和文件上传的堆栈溢出问题的链接,其中有关于这个问题的更多信息。

有两种可能的解决方案可以解决此问题。第一个是您使用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;
  }

另一种方法是您自己构建 FormData 对象,方法是自己在代码中添加所选文件,然后再将其发送到服务器。这应该在任何地方都可以正常工作。这是一个示例代码:

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

我还创建了一个StackBlitz 示例,您可以在其中查看所有代码。

【讨论】:

  • 很好的答案。我知道我可以以某种方式附加文件对象,但我想避免它,拥有一种形式而不附加额外的东西感觉更合适。无论如何,我会附加它,因为我找不到任何其他解决方案。现在的问题是节点中的强大表示文件和字段都未定义。我无法命名附加字段 imageInput,因为已经有另一个。从 formData 中删除字段不是一种选择,因为并非所有浏览器都支持删除字段。我把 form.multiples = true; 放在了 formidable 中,但仍然不确定。有任何想法吗?谢谢 JS stack 讨厌我....
  • 我建议您像在第二个示例中那样构建一个新的 FormData 对象。并且不重复使用原来的。如果您还使用表单发送其他数据,您当然也需要手动附加所有其他值。这是一项工作,但他的方式是您不会获得两个文件条目。另一种选择是添加具有不同名称的拖放文件,然后在服务器上检查两者并仅使用具有正确数据的文件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-27
  • 2021-04-26
  • 2021-06-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多