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

如何配置ASP.NET Core 6+Vue单应用部署至IIS/Azure WebApp(解决404)

解决ASP.NET Core 6 Web API与Vue.js单应用部署的404问题

我需要将ASP.NET Core 6 Web API与Vue.js前端作为单个应用部署至IIS,后续计划部署到Azure WebApp。已执行npm run build并将/dist目录文件复制到API发布目录的/Apps/文件夹下,但访问http://localhost:5000/Apps/时出现HTTP 404未找到错误,怀疑应用无法找到index.html或未配置相关路径。现有配置如下:

Program.cs代码

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        // Add services to the container.
        builder.Services.AddControllers();
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();
        builder.Services.AddDbContext<ApplicationDbContext>(c => c.UseSqlServer(builder.Configuration["DBConnection:ConnectionString"], builder =>
        {
            builder.EnableRetryOnFailure(3, TimeSpan.FromSeconds(10), null);
            builder.CommandTimeout(10800);
        }), ServiceLifetime.Transient);

        builder.Services.AddIdentity<ApplicationUser, Role>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

        builder.Services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        })
            .AddJwtBearer(options =>
            {
                //options.SaveToken = true;
                options.RequireHttpsMetadata = false;
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuer = true,
                    ValidIssuer = "https://accounts.google.com",
                    ValidateAudience = true,
                    ValidAudience = "http://localhost:8080/",
                    ValidateLifetime = true,
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JWT:Secret"])),
                    ClockSkew = TimeSpan.FromSeconds(5) //invalidate expied token.
                };
                options.Events = new JwtBearerEvents()
                {
                    OnChallenge = context =>
                    {
                        if (context.Error == "invalid_token")
                            return Task.FromException(new HttpResponseException(HttpStatusCode.Unauthorized));
                        //custom logic goes here.  At the end of your logic make sure that you
                        //"Handle" the response by calling HandleResponse, and return a 0.
                        context.HandleResponse();
                        return Task.FromResult(0);
                    }
                };
            });

        builder.Services.AddScoped<IUserService, UserService>();
        builder.Services.AddScoped<IUserRepository, UserRepository>();

        builder.Services.AddCors(options =>
        {
            options.AddPolicy("AllowGoogleOAuth", policyBuilder =>
            {
                policyBuilder.WithOrigins("https://accounts.google.com", builder.Configuration["Client:URL"]);
                policyBuilder.WithHeaders("Content-Type", "Authorization", "Access-Control-Allow-Headers", "Access-Control-Allow-Methods", "Access-Control-Allow-Credentials", "Access-Control-Allow-Origin");
                policyBuilder.WithMethods("GET", "POST", "PUT", "DELETE", "PATCH");
                policyBuilder.AllowCredentials(); // Allow credentials
            });
        });

        var app = builder.Build();

        if (app.Environment.IsDevelopment())
        {
            app.UseSwagger();
            app.UseSwaggerUI();
        }

        app.UseCors("AllowGoogleOAuth");
        app.UseAuthentication(); // Add this line before UseAuthorization
        app.UseAuthorization();
        app.MapControllers();
        app.Run();
    }
}

Vue配置

const router = createRouter({
  history: createWebHistory(process.env.VUE_APP_BASE_URL),
  routes
})
....
VUE_APP_BASE_URL = "/Apps/"

核心问题分析

当前ASP.NET Core应用未启用静态文件服务,无法识别/Apps/目录下的Vue打包文件;同时Vue使用history路由模式,缺少路由回退规则,导致刷新或直接访问子路由时出现404。

具体配置方案

1. 修改ASP.NET Core的Program.cs配置

添加静态文件服务配置,并设置SPA路由回退,调整后的代码如下:

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        // 原有服务注册代码保持不变
        builder.Services.AddControllers();
        builder.Services.AddEndpointsApiExplorer();
        builder.Services.AddSwaggerGen();
        // ...(省略其他服务注册代码)

        var app = builder.Build();

        if (app.Environment.IsDevelopment())
        {
            app.UseSwagger();
            app.UseSwaggerUI();
        }

        app.UseCors("AllowGoogleOAuth");

        // 1. 配置静态文件服务,映射/Apps请求到物理目录的Apps文件夹
        app.UseStaticFiles(new StaticFileOptions
        {
            RequestPath = "/Apps",
            FileProvider = new PhysicalFileProvider(
                Path.Combine(Directory.GetCurrentDirectory(), "Apps"))
        });

        app.UseAuthentication();
        app.UseAuthorization();

        app.MapControllers();

        // 2. 配置SPA路由回退,所有/Apps下的非API请求都返回index.html
        app.MapFallbackToFile("/Apps/{*path:nonfile}", "/Apps/index.html");

        app.Run();
    }
}

关键说明:

  • UseStaticFiles:启用静态文件服务,指定请求路径/Apps对应物理目录的Apps文件夹,让ASP.NET Core能找到Vue打包后的静态资源。
  • MapFallbackToFile:针对/Apps/下的所有非文件请求(即Vue路由路径),返回index.html,解决history模式下的刷新404问题。

2. 验证Vue打包配置

确保Vue的基础路径配置正确,打包后的资源路径能被ASP.NET Core正确识别:

  • 确认.env文件中的VUE_APP_BASE_URL = "/Apps/"无误
  • 执行npm run build后,检查dist目录下的index.html中,所有静态资源的引用路径是否以/Apps/开头(如<script src="/Apps/js/app.xxx.js"></script>)

3. IIS部署额外注意事项

  • 确保IIS站点的应用程序池设置为.NET Core模式(无托管代码)
  • 部署到Azure WebApp时,无需额外配置IIS,上述ASP.NET Core配置即可生效,只需确保发布包中包含Apps目录及其内容

测试步骤

  1. 重新发布ASP.NET Core应用,确保Apps目录包含Vue打包后的所有文件
  2. 启动应用,访问http://localhost:5000/Apps/,确认能正常加载Vue页面
  3. 测试Vue路由跳转和页面刷新,确保不会出现404

内容的提问来源于stack exchange,提问作者Bogdan Andrei

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 18:47:34