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获取数据