Angular 18与.NET 8文件上传问题咨询及方案疑问
我尝试从Angular 18应用向.NET 8 Web API上传文件(最终通过服务存入AWS S3桶),但上传失败。用Postman调用API时,控制器能正常识别文件名;但通过Angular应用上传时,控制器始终显示文件数量为0。网络面板和控制台能看到请求已提交FormData,但控制器就是接收不到任何文件。
核心疑问:是否必须将文件Base64编码后传给API再写入S3?还是可以直接用FormData提交文件到API并存入S3?
Angular 18 相关代码
upload.component.html
<div class="card mb-4"> <div class="card-header"> <strong>Upload</strong> </div> <div class="card-body"> <div class="upload-section mb-3"> <label for="fileUpload" class="form-label">Select File</label> <input type="file" id="fileUpload" (change)="onFileSelected($event)" class="form-control" multiple /> </div> <div class="d-flex justify-content-end"> <button type="button" class="btn btn-primary me-2" (click)="uploadDocuments()" > Upload </button> <button type="button" class="btn btn-secondary" (click)="resetDocuments()" > Reset </button> </div> </div> </div>
upload.component.ts
onFileSelected(event: any) { if (event.target.files && event.target.files.length > 0) { const files: FileList = event.target.files; for (let i = 0; i < files.length; i++) { this.selectedDocuments.push(files[i]); } } } uploadDocuments() { if (this.selectedDocuments.length > 0) { this.uploadProgress = 0; // Reset progress this.documentService.uploadDocuments(this.selectedDocuments).subscribe({ next: (event) => { if (event.type === HttpEventType.UploadProgress && event.total) { this.uploadProgress = Math.round((100 * event.loaded) / event.total); } else if (event instanceof HttpResponse) { console.log('Documents uploaded successfully:', event.body); alert('Documents uploaded successfully!'); this.selectedDocuments = []; // Clear the list after uploading this.uploadProgress = 0; // Reset progress } }, error: (error) => { console.error('Error uploading documents:', error); alert('An error occurred during document upload.'); } }); } else { alert('There are no documents selected for upload.'); } }
upload.service.ts
uploadDocuments(files: File[]): Observable<HttpEvent<any>> { const formData = new FormData(); files.forEach(file => { formData.append('files', file, file.name); }); console.log('FormData:', formData); // Just to check the formData contents formData.forEach((value, key) => { console.log(`Key: ${key}, Value:`, value); }); console.log('FormData size:', formData.getAll('files').length); const req = new HttpRequest('POST', `${this.apiUrl}/documents/upload`, formData, { reportProgress: true, // Enable progress tracking responseType: 'json' }); return this.http.request(req).pipe( catchError(this.handleError) // Handle errors properly ); }
.NET 8 Web API 控制器代码
[HttpPost("upload"), DisableRequestSizeLimit] public async Task<IActionResult> UploadDocuments([FromForm] IFormFileCollection files) { if (files.Count == 0) { return BadRequest("No files selected."); } await _documentService.UploadDocumentsAsync(files, GetOrganizationName()); return Ok("Files uploaded successfully."); }
问题解答
核心结论
完全不需要Base64编码,直接用FormData提交文件到API再存入S3是可行的——Postman能成功就是最好的证明。你的问题出在Angular请求配置或跨域设置上,以下是具体排查和修复方向:
不要手动设置Content-Type
Angular发送FormData时会自动添加multipart/form-data头并生成正确的boundary值,手动设置这个头会破坏请求结构,确保你的代码没加类似headers: {'Content-Type': 'multipart/form-data'}的配置。检查跨域(CORS)配置
.NET后端的CORS策略必须允许表单数据上传,在Program.cs中确保配置包含:builder.Services.AddCors(options => { options.AddPolicy("AllowAngular", policy => { policy.WithOrigins("你的Angular应用地址") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); }); app.UseCors("AllowAngular");确认参数名严格匹配
你的FormData键是files,后端参数也是files,这部分没问题,但要检查是否有大小写或拼写错误。调整文件大小限制
虽然加了DisableRequestSizeLimit,大文件上传还需在appsettings.json补充配置:"Kestrel": { "Limits": { "MaxRequestBodySize": 52428800 // 50MB,按需调整 } }验证实际请求内容
在浏览器Network面板查看请求的FormData部分,确认文件是否真的被包含在请求体里——控制台打印FormData可能显示不全,实际请求内容才是准确依据。
正确流程
确认上述配置无误后,直接用FormData提交文件,后端接收IFormFileCollection,然后将文件流直接传给AWS S3 SDK(比如PutObjectAsync)即可,Base64编码会让文件体积增大30%,完全没必要。
内容的提问来源于stack exchange,提问作者Sat

