You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular14+ASP.NET Core6 WebAPI上传文件展示与下载功能求助

ASP.NET Core 后端完善

1. 文件列表与下载接口

完善接口逻辑,增加异常处理、文件信息格式化,同时优化配置灵活性:

using Microsoft.AspNetCore.Mvc;
using System.IO;

[ApiController]
[Route("api/files")]
public class FilesController : ControllerBase
{
    private readonly string _uploadPath;

    // 从配置文件读取上传路径,避免硬编码
    public FilesController(IConfiguration configuration)
    {
        var uploadDir = configuration["FileSettings:UploadPath"] ?? "Uploads";
        _uploadPath = Path.Combine(Directory.GetCurrentDirectory(), uploadDir);
    }

    [HttpGet("list")]
    public IActionResult GetFileList()
    {
        try
        {
            if (!Directory.Exists(_uploadPath))
            {
                Directory.CreateDirectory(_uploadPath);
                return Ok(new List<FileInfoDto>());
            }

            var files = new DirectoryInfo(_uploadPath)
                .GetFiles()
                .Select(f => new FileInfoDto
                {
                    FileName = f.Name,
                    FileSize = FormatFileSize(f.Length),
                    CreatedTime = f.CreationTime.ToString("yyyy-MM-dd HH:mm:ss")
                })
                .ToList();

            return Ok(files);
        }
        catch (Exception ex)
        {
            return StatusCode(500, $"获取文件列表失败: {ex.Message}");
        }
    }

    [HttpGet("download/{fileName}")]
    public IActionResult DownloadFile(string fileName)
    {
        try
        {
            // 处理文件名编码,避免特殊字符问题
            var decodedFileName = Uri.UnescapeDataString(fileName);
            var filePath = Path.Combine(_uploadPath, decodedFileName);

            if (!System.IO.File.Exists(filePath))
            {
                return NotFound("文件不存在");
            }

            var contentType = GetContentType(decodedFileName);
            // 使用FileStream减少内存占用,支持大文件下载
            var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            return File(stream, contentType, decodedFileName);
        }
        catch (Exception ex)
        {
            return StatusCode(500, $"下载文件失败: {ex.Message}");
        }
    }

    // 格式化文件大小为易读格式
    private string FormatFileSize(long bytes)
    {
        return bytes switch
        {
            < 1024 => $"{bytes} B",
            < 1048576 => $"{bytes / 1024:F2} KB",
            < 1073741824 => $"{bytes / 1048576:F2} MB",
            _ => $"{bytes / 1073741824:F2} GB"
        };
    }

    // 获取文件MIME类型
    private string GetContentType(string fileName)
    {
        var provider = new Microsoft.AspNetCore.StaticFiles.FileExtensionContentTypeProvider();
        return provider.TryGetContentType(fileName, out var contentType) 
            ? contentType 
            : "application/octet-stream";
    }
}

// 数据传输对象
public class FileInfoDto
{
    public string FileName { get; set; }
    public string FileSize { get; set; }
    public string CreatedTime { get; set; }
}

关键配置补充

  1. 在appsettings.json添加文件路径配置:
{
  "FileSettings": {
    "UploadPath": "Uploads"
  }
}
  1. 配置CORS允许前端访问:
// Program.cs
builder.Services.AddCors(options =>
{
    options.AddPolicy("AllowAngular", policy =>
        policy.WithOrigins("http://localhost:4200")
              .AllowAnyHeader()
              .AllowAnyMethod());
});

app.UseCors("AllowAngular");

Angular 前端完善

1. 文件服务(file.service.ts)

封装HTTP请求,处理文件列表获取与下载逻辑:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

export interface FileInfo {
  fileName: string;
  fileSize: string;
  createdTime: string;
}

@Injectable({
  providedIn: 'root'
})
export class FileService {
  private apiUrl = 'http://localhost:5000/api/files';

  constructor(private http: HttpClient) { }

  getFileList(): Observable<FileInfo[]> {
    return this.http.get<FileInfo[]>(`${this.apiUrl}/list`);
  }

  downloadFile(fileName: string): Observable<Blob> {
    // 对文件名编码,避免特殊字符传递异常
    const encodedFileName = encodeURIComponent(fileName);
    return this.http.get(`${this.apiUrl}/download/${encodedFileName}`, {
      responseType: 'blob'
    });
  }
}

2. 组件逻辑(file-list.component.ts)

实现文件列表加载与下载功能,添加状态提示:

import { Component, OnInit } from '@angular/core';
import { FileService, FileInfo } from '../services/file.service';

@Component({
  selector: 'app-file-list',
  templateUrl: './file-list.component.html',
  styleUrls: ['./file-list.component.css']
})
export class FileListComponent implements OnInit {
  fileList: FileInfo[] = [];
  errorMessage = '';
  isLoading = false;

  constructor(private fileService: FileService) { }

  ngOnInit(): void {
    this.loadFileList();
  }

  loadFileList(): void {
    this.isLoading = true;
    this.fileService.getFileList().subscribe({
      next: files => {
        this.fileList = files;
        this.errorMessage = '';
        this.isLoading = false;
      },
      error: err => {
        this.errorMessage = err.error || '加载文件列表失败';
        this.isLoading = false;
      }
    });
  }

  downloadFile(fileName: string): void {
    this.fileService.downloadFile(fileName).subscribe({
      next: blob => {
        const url = window.URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = fileName;
        document.body.appendChild(a);
        a.click();
        // 清理资源
        window.URL.revokeObjectURL(url);
        document.body.removeChild(a);
      },
      error: err => {
        this.errorMessage = err.error || '下载文件失败';
      }
    });
  }
}

3. 页面模板(file-list.component.html)

展示文件列表,添加加载状态与错误提示:

<div class="container mt-4">
  <h2>服务器文件列表</h2>
  
  <!-- 加载状态 -->
  <div *ngIf="isLoading" class="text-center">
    <div class="spinner-border" role="status">
      <span class="visually-hidden">加载中...</span>
    </div>
  </div>

  <!-- 错误提示 -->
  <div *ngIf="errorMessage && !isLoading" class="alert alert-danger mt-3">{{ errorMessage }}</div>

  <!-- 文件列表表格 -->
  <table *ngIf="!isLoading" class="table table-striped mt-3">
    <thead>
      <tr>
        <th>文件名</th>
        <th>文件大小</th>
        <th>创建时间</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <tr *ngFor="let file of fileList">
        <td>{{ file.fileName }}</td>
        <td>{{ file.fileSize }}</td>
        <td>{{ file.createdTime }}</td>
        <td>
          <button class="btn btn-primary" (click)="downloadFile(file.fileName)">下载</button>
        </td>
      </tr>
      <tr *ngIf="fileList.length === 0 && !errorMessage">
        <td colspan="4" class="text-center text-muted">暂无文件</td>
      </tr>
    </tbody>
  </table>
</div>

必要配置

确保AppModule中导入HttpClientModule:

import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [HttpClientModule],
})
export class AppModule { }

额外优化建议
  • 添加文件删除功能:后端实现删除接口,前端增加删除按钮并确认提示
  • 支持文件搜索、排序:前端添加搜索框,对文件名进行过滤,或按创建时间/大小排序
  • 限制文件访问权限:后端添加身份验证,仅允许授权用户查看和下载文件
  • 大文件下载优化:后端支持断点续传,前端显示下载进度

内容的提问来源于stack exchange,提问作者salah afourer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 19:23:16