Angular 4打字稿中的文件上传和下载

Posted

技术标签:

【中文标题】Angular 4打字稿中的文件上传和下载【英文标题】:File upload and download in angular 4 typescript 【发布时间】:2017-12-22 23:21:56 【问题描述】:

如何下​​载(位于根路径中的.exe 文件)并从 Angular 4 上传文件? 我是 Angular4 和 typescript 以及 .NET Core Web API 的新手。

我已经搜索过这个,但找不到解决方案。

以下是我发现的一些类似问题:

Uploading file to controller using typescript

Returning binary file from controller in ASP.NET Web API

【问题讨论】:

试试typescript的ResponseContentType.Blob函数 【参考方案1】:

我想为此添加一个 Angular 4.3/5/6/7/8 更新,特别是相对于简化的 HttpClient。 'Content-Type' 的缺失尤其重要,因为 Angular 会自动构造 Content-Type(有添加 Content-Type=undefined 的倾向。不要,因为它会在各种情况下产生问题,也许不会好的做法)。一旦没有 Content-Type,浏览器会自动添加 'multipart/form-data' 和相关参数。请注意,这里的后端是 Spring Boot,尽管它应该无关紧要。

这里有一些伪代码——请原谅大拇指。希望这会有所帮助:

MyFileUploadComponent(.html):

...
<input type="file" (change)=fileEvent($event)...>

MyFileUploadComponent(.ts) 在 fileEvent 上调用 MyFileUploadService(.ts):

...
public fileEvent($event) 
   const fileSelected: File = $event.target.files[0];
   this.myFileUploadService.uploadFile(fileSelected)
   .subscribe( (response) => 
      console.log('set any success actions...');
      return response;
    ,
     (error) => 
       console.log('set any error actions...');
     );

MyFileUploadService.ts:

...
public uploadFile(fileToUpload: File) 
  const _formData = new FormData();
  _formData.append('file', fileToUpload, fileToUpload.name);   
  return<any>post(UrlFileUpload, _formData); 
  //note: no HttpHeaders passed as 3rd param to POST!
  //So no Content-Type constructed manually.
  //Angular 4.x-6.x does it automatically.

  

【讨论】:

我发现这个答案是完成任务的最佳简单方法。 嗨 MoMo 感谢您的解决方案,_formData 显示为空对象。喜欢 。请建议我如何将文件发送到服务器。 返回post() ?真的吗?【参考方案2】:

使用 Angular 8+ 和 ASP.NET CORE 2+ 版本从服务器下载任何文件。

下载文件的控制器实现:

[HttpGet] [路线(“下载”)] 公共异步任务下载([FromQuery] 字符串文件) var uploads = Path.Combine(_hostingEnvironment.WebRootPath, "uploads"); var filePath = Path.Combine(上传,文件); if (!System.IO.File.Exists(filePath)) 返回未找到(); var memory = new MemoryStream(); 使用 (var stream = new FileStream(filePath, FileMode.Open)) 等待流.CopyToAsync(内存); 内存.位置 = 0; 返回文件(内存,GetContentType(文件路径),文件);

创建角度服务

从'@angular/core'导入可注射; 从“@angular/common/http”导入 HttpClient、HttpRequest、HttpEvent、HttpResponse ; 从'rxjs'导入 Observable ; @Injectable() 导出类下载服务 私有baseApiUrl:字符串; 私有 apiDownloadUrl:字符串; 私有 apiUploadUrl:字符串; 私有 apiFileUrl:字符串; 构造函数(私有 httpClient:HttpClient) this.baseApiUrl = 'http://localhost:5001/api/'; this.apiDownloadUrl = this.baseApiUrl + '下载'; this.apiUploadUrl = this.baseApiUrl + '上传'; this.apiFileUrl = this.baseApiUrl + '文件'; 公共下载文件(文件:字符串):Observable> 返回 this.httpClient.request(new HttpRequest( '得到', `$this.apiDownloadUrl?file=$file`, 空值, 报告进度:真, 响应类型:'blob' ));

用角度创建模型

导出接口 ProgressStatus 状态:进度状态枚举; 百分比?:数字; 导出枚举 ProgressStatusEnum 开始、完成、IN_PROGRESS、错误

创建一个组件来下载文件

下载

创建一个子组件来下载文件。打字稿文件中的以下代码:

从'@angular/core'导入组件、输入、输出、事件发射器; 从“@angular/common/http”导入 HttpEventType ; 从'src/app/services/upload-download.service'导入 UploadDownloadService ; 从 'src/app/models/progress-status.model' 导入 ProgressStatus, ProgressStatusEnum ; @零件( 选择器:'应用程序下载', 模板网址:'download.component.html' ) 导出类下载组件 @Input() 公共禁用:布尔值; @Input() 公共文件名:字符串; @Output() 公共下载状态:EventEmitter; 构造函数(私人服务:UploadDownloadService) this.downloadStatus = new EventEmitter(); 公共下载() this.downloadStatus.emit(status: ProgressStatusEnum.START); this.service.downloadFile(this.fileName).subscribe( 数据 => 开关(数据类型) 案例 HttpEventType.DownloadProgress: this.downloadStatus.emit(状态:ProgressStatusEnum.IN_PROGRESS,百分比:Math.round((data.loaded / data.total)* 100)); 休息; 案例 HttpEventType.Response: this.downloadStatus.emit(状态:ProgressStatusEnum.COMPLETE); const 下载文件 = new Blob([data.body], type: data.body.type ); const a = document.createElement('a'); a.setAttribute('style', 'display:none;'); document.body.appendChild(a); a.download = this.fileName; a.href = URL.createObjectURL(downloadedFile); a.target = '_blank'; a.点击(); document.body.removeChild(a); 休息; , 错误 => this.downloadStatus.emit(status: ProgressStatusEnum.ERROR); );

在父组件中添加如下实现:

进度 percentage%

在父 typescript 组件中添加以下实现:

从'@angular/core'导入组件,OnInit; 从'src/app/services/upload-download.service'导入 UploadDownloadService ; 从 'src/app/models/progress-status.model' 导入 ProgressStatusEnum, ProgressStatus ; @零件( 选择器:'应用程序文件管理器', 模板网址:'./file-manager.component.html' ) 导出类 FileManagerComponent 实现 OnInit 公共文件:字符串[]; 公共文件下载:字符串; 公共百分比:数字; public showProgress:布尔值; 公共显示下载错误:布尔值; 公共显示上传错误:布尔值; 构造函数(私人服务:UploadDownloadService) ngOnInit() this.getFiles(); 私人 getFiles() this.service.getFiles().subscribe( 数据 => this.files = 数据; ); 公共下载状态(事件:ProgressStatus) 开关(事件.状态) 案例 ProgressStatusEnum.START: this.showDownloadError = false; 休息; 案例 ProgressStatusEnum.IN_PROGRESS: this.showProgress = true; this.percentage = event.percentage; 休息; 案例 ProgressStatusEnum.COMPLETE: this.showProgress = false; 休息; 案例 ProgressStatusEnum.ERROR: this.showProgress = false; this.showDownloadError = true; 休息;

完成!

【讨论】:

【参考方案3】:

请参考以下代码进行文件上传。 html代码:

<div class="col-md-6">
     <label class="control-heading">Select File</label>
     <input type="file" [multiple]="multiple" #fileInput (change)="selectFile($event)">
     <input type="button" style="margin-top: 15px;" [disabled]="!isUploadEditable" class="data-entry-button btn-pink" (click)="uploadFile()" value="Upload" title="globalService.generateTooltip('upload attachment','Click to upload document.')" data-html="true" data-toggle="tooltip" data-placement="bottom" />
</div>

组件代码:

selectFile(event: any) 
    this.selectedFiles = event.target.files;


uploadFile() 
    this.currentFileUpload = this.selectedFiles.item(0);
    this.globalService.pushFileToStorage(this.currentFileUpload).subscribe(event => 
        if (event instanceof HttpResponse) 
            this.loadDocumentInfo();
            this.showNotification('Upload Attachment', 'File Uploaded Successfully', 'success');
            this.myInputVariable.nativeElement.value = "";
        
    );
    this.selectedFiles = undefined;

全球服务代码:

pushFileToStorage(file: File): Observable<HttpEvent<>> 
    const formdata: FormData = new FormData();
    formdata.append('file', file);
    formdata.append('documentVersionId', this.documentVersionId.toString());
    formdata.append('levelId', this.levelId);
    formdata.append('levelKey', this.levelKey);
    formdata.append('LoggedInUser', this.loggedInUser);
    const req = new HttpRequest('POST', this.urlService.CMMService + '/CMMService-service/UploadFileAsAttachment', formdata, 
        reportProgress: true,
        responseType: 'text'
    
    );
    return this.http.request(req);

使用文件名和文件路径下载文件:

以文件名和文件路径为参数从 html 调用 DownloadFile 函数。

组件代码:

DownloadFile(filePath: string, filename: string) 
    this.globalService.DownloadFile(filePath).subscribe(res => 
        //console.log('start download:', res);
        var url = window.URL.createObjectURL(res);
        var a = document.createElement('a');
        document.body.appendChild(a);
        a.setAttribute('style', 'display: none');
        a.href = url;
        res.filename = filename;
        a.download = res.filename;
        a.click();
        window.URL.revokeObjectURL(url);
        a.remove(); // remove the element
    , error => 
        console.log('download error:', JSON.stringify(error));
    , () => 
        console.log('Completed file download.')
    );

全球服务代码下载文件:

public DownloadFile(filePath: string): Observable<any> 
   return this.http
        .get(this.urlService.CMMService + '/CMMService-service/DownloadFile?filePath=' + filePath, 
            responseType: 'blob'
        );

在服务器端请使用以下代码:

[HttpGet]
        [ODataRoute("DownloadFile")]
        public HttpResponseMessage DownloadFile(string filePath)
        
            var fileData = CommonDomain.DownloadFileFromS3(filePath);
            var dataStream = new MemoryStream(fileData.ByteArray);
            HttpResponseMessage httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK);
            httpResponseMessage.Content = new StreamContent(dataStream);
            httpResponseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
            httpResponseMessage.Content.Headers.ContentDisposition.FileName = fileData.FileName;
            httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
            httpResponseMessage.Content.Headers.Add("x-filename", fileData.FileName);
            return httpResponseMessage;
        

如果你们仍然遇到任何问题,请告诉我。

【讨论】:

【参考方案4】:

用角度下载文件试试这个,它可以工作`

download(row) 
    return this.Http
      .get(file_path , 
        responseType: ResponseContentType.Blob,
      )
      .map(res => 
        return 
          filename: row.name,
          data: res.blob()
        ;
      )
      .subscribe(res => 
        let url = window.URL.createObjectURL(res.data);
        let a = document.createElement('a');
        document.body.appendChild(a);
        a.setAttribute('style', 'display: none');
        a.href = url;
        a.download = res.filename;
        a.click();
        window.URL.revokeObjectURL(url);
        a.remove();
      );
  

`

【讨论】:

【参考方案5】:

对于上传文件,我们可以以 multipart/form-data 的形式发布数据。为此,我们必须使用 FormData 类。这是一个例子。

模板:

<form #yourForm="ngForm" (ngSubmit)="onSubmit()">
      <input type="text" [(ngModel)]="Name" name="Name"/>
      <input type="file" #fileupload [(ngModel)]="myFile" name="myFile" (change)="fileChange(fileupload.files)"/>
      <button type="submit">Submit</button>
</form>

组件:

import  Http, Response, Headers, RequestOptions  from '@angular/http';
/* When we select file */
Name:string; 
myFile:File; /* property of File type */
fileChange(files: any)
    console.log(files);

    this.myFile = files[0].nativeElement;


/* Now send your form using FormData */
onSubmit(): void 
    let _formData = new FormData();
    _formData.append("Name", this.Name);
    _formData.append("MyFile", this.myFile);
    let body = this._formData;
    let headers = new Headers();
    let options = new Options(
        headers: headers
    );
    this._http.post("http://example/api/YourAction", body, options)
      .map((response:Response) => <string>response.json())
      .subscribe((data) => this.message = data);

上传文件的API见:https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-2

【讨论】:

我在 this.myFile = files[0] 中遇到错误; as Uncaught (in promise): InvalidStateError: Failed to set the 'value' property on 'HTMLInputElement': 此输入元素接受文件名,该文件名只能以编程方式设置为空字符串。 魔术!您使用Headers()Options()。它们是从哪里进口的?角?别的地方?如果是 Angular,那么 Angular 在哪里?关心给出全方位的答案。天哪。【参考方案6】:
<form [formGroup]="uploadForm" (ngSubmit)="onSubmit()">
    Select image to upload:
    <input type="file" name="avatar" id="fileToUpload" formControlName="file1" (change)="fileEvent($event)">
    <input type="submit" value="Upload Image" name="submit">
</form>
import  Component, OnInit  from '@angular/core';
import  FormControl, FormGroup  from '@angular/forms';
import  HttpClient  from '@angular/common/http';
@Component(
  selector: 'app-praveen',
  templateUrl: './praveen.component.html',
  styleUrls: ['./praveen.component.css']
)
export class PraveenComponent implements OnInit 

  constructor(private httpClient:HttpClient)  
    uploadForm = new FormGroup (
        file1: new FormControl()
    );
    filedata:any;
    fileEvent(e)
        this.filedata=e.target.files[0];
        console.log(e);
    
    onSubmit() 
        let formdata = new FormData();
        console.log(this.uploadForm)
        formdata.append("avatar",this.filedata);
        this.httpClient
        .post<any>("http://localhost:3040/uploading",formdata)
        .subscribe((res)=>console.log(res);
    
  ngOnInit() 
  


【讨论】:

它帮助了我:)【参考方案7】:

非常简单 component.html 看起来像

<div class="form-group col-md-6" style="margin-left:50%;margin-top:-8%" >
    <input type="file" value="upload" accept=".jpg" (change)=fileUploader($event)>
</div>

在 ts 文件中,它看起来像

public fileUploader(event) 
    const elem = event.target;
    if (elem.files.length > 0) 
        console.log(elem.files[0]);
    
    // ...

【讨论】:

以上是关于Angular 4打字稿中的文件上传和下载的主要内容,如果未能解决你的问题,请参考以下文章

Angular 2 - 如何在打字稿中使用 FileReader 从给定的 URL 读取文件?

MEAN STACK angular 2:从打字稿中的多个api获取数据

打字稿中的模块关键字是啥意思?

如何从 Angular 6 中的另一个组件的打字稿中激活和停用组件中的样式?

动态生成的网格无法在 Angular 2 打字稿中拖动

使用打字稿将文件上传到控制器