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

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

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

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

【问题讨论】:

  • 试试typescript的ResponseContentType.Blob函数

标签: angular typescript asp.net-core-webapi


【解决方案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]);
            }
            // ...
        }
        

        【讨论】:

          猜你喜欢
          • 2017-08-20
          • 1970-01-01
          • 1970-01-01
          • 2019-04-12
          • 2023-03-29
          • 1970-01-01
          • 2023-04-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多