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

Angular结合Docker/docker-compose部署后本地页面无法访问

Angular+ASP.NET Core Docker部署后页面无法访问问题排查

我本地可以正常运行Angular应用,但通过Docker部署后出现“本地页面无法找到”的问题(docker-compose中还有其他未列出的服务)。以下是我的配置信息:

Docker-compose配置

version: '3.4'
services:

shopfrontspa:
container_name: lost_chapters_shop_front
image: ${DOCKER_REGISTRY-}shopfrontspa
build:
  context: .
  dockerfile: FrontEnds/ShopFrontSpa/Dockerfile
networks:
 - lost_chapters_network

Docker-compose.override配置

version: '3.4'

services:
shopfrontspa:
environment:
  - ASPNETCORE_ENVIRONMENT=Development
  - ASPNETCORE_URLS=https://+:443;http://+:80
ports:
  - "5110:80"
  - "7110:443"
volumes:
  - ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro
  - ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro

networks:
lost_chapters_network:
 external: true

Dockerfile配置

FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["FrontEnds/ShopFrontSpa/ShopFrontSpa.csproj", "FrontEnds/ShopFrontSpa/"]
RUN dotnet restore "FrontEnds/ShopFrontSpa/ShopFrontSpa.csproj"
COPY . .
WORKDIR "/src/FrontEnds/ShopFrontSpa"
RUN dotnet build "ShopFrontSpa.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "ShopFrontSpa.csproj" -c Release -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ShopFrontSpa.dll"]

Package.json配置

"name": "shopfrontspa",
 "version": "0.0.0",
 "scripts": {
"ng": "ng",
"prestart": "node aspnetcore-https",
"start": "run-script-os",
//"start": "ng serve --host 0.0.0.0",
"start:windows": "ng serve --port 44436 --ssl --ssl-cert 
%APPDATA%\\ASP.NET\\https\\%npm_package_name%.pem --ssl-key 
%APPDATA%\\ASP.NET\\https\\%npm_package_name%.key",
"start:default": "ng serve --port 44436 --ssl --ssl-cert 
$HOME/.aspnet/https/${npm_package_name}.pem --ssl-key 
$HOME/.aspnet/https/${npm_package_name}.key",
"build": "ng build",
"build:ssr": "ng run ShopFrontSpa:server:dev",
"watch": "ng build --watch --configuration development",
"test": "ng test"

Program.cs配置

var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseContentRoot(Directory.GetCurrentDirectory());

// Add services to the container.
builder.Services.Configure<AppSettings>(builder.Configuration);
builder.Services.AddCors(options =>
{
    options.AddPolicy("CorsPolicy",
        builder => builder
        .SetIsOriginAllowed((host) => true)
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials());
});
builder.Services.AddControllersWithViews().AddJsonOptions(options => { options.JsonSerializerOptions.PropertyNameCaseInsensitive = true; });
builder.Services.AddHttpClient<IOrderService, OrderService>(p =>
{
    //p.BaseAddress = new Uri(builder.Configuration["MicroservicAddress:ApiGatewayForWeb:Uri"]);
});

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}
app.UseCors("CorsPolicy");
// Here we add Angular default Antiforgery cookie name on first load. https://angular.io/guide/http#security-xsrf-protection
// This cookie will be read by Angular app and its value will be sent back to the application as the header configured in .AddAntiforgery()
//app.Use((context, next) =>
//{
//    string path = context.Request.Path.Value;
//    //Do work that does not write to the Response
//    return next(context);
//    //Do logging or other work that does not write to the Response.
//});

var pathBase = app.Configuration["PATH_BASE"];

if (!string.IsNullOrEmpty(pathBase))
{
    app.UsePathBase(pathBase);
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseEndpoints(endpoints =>
{
    endpoints.MapDefaultControllerRoute();
    endpoints.MapControllers();
    
});

app.MapFallbackToFile("index.html"); ;

// Handles all still unnatended (by any other middleware) requests by returning the default page of the SPA (wwwroot/index.html).
app.UseSpa(spa =>
{
    // To learn more about options for serving an Angular SPA from ASP.NET Core,
    // see https://go.microsoft.com/fwlink/?linkid=864501

    // the root of the angular app. (Where the package.json lives)
    spa.Options.SourcePath = "Client";

    if (app.Environment.IsDevelopment())
    {

        // use the SpaServices extension method for angular, that will make the application to run "ng serve" for us, when in development.
        spa.UseAngularCliServer(npmScript: "start");
    }
});

app.Run();

应用运行日志

2023-05-02 13:06:04 warn: 

Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
2023-05-02 13:06:04       Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
2023-05-02 13:06:04 warn: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[35]
2023-05-02 13:06:04       No XML encryptor configured. Key {47f19310-8c91-40f1-a9a1-8599d772d586} may be persisted to storage in unencrypted form.
2023-05-02 13:06:04 info: Microsoft.Hosting.Lifetime[14]
2023-05-02 13:06:04       Now listening on: https://[::]:443
2023-05-02 13:06:04 info: Microsoft.Hosting.Lifetime[14]
2023-05-02 13:06:04       Now listening on: http://[::]:80
2023-05-02 13:06:04 info: Microsoft.Hosting.Lifetime[0]
2023-05-02 13:06:04       Application started. Press Ctrl+C to shut down.
2023-05-02 13:06:04 info: Microsoft.Hosting.Lifetime[0]
2023-05-02 13:06:04       Hosting environment: Development
2023-05-02 13:06:04 info: Microsoft.Hosting.Lifetime[0]
2023-05-02 13:06:04       Content root path: /app/
2023-05-02 13:19:29 warn: Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository[60]
2023-05-02 13:19:29       Storing keys in a directory '/root/.aspnet/DataProtection-Keys' that may not be persisted outside of the container. Protected data will be unavailable when container is destroyed.
2023-05-02 13:19:29 info: Microsoft.Hosting.Lifetime[14]
2023-05-02 13:19:29       Now listening on: https://[::]:443
2023-05-02 13:19:29 info: Microsoft.Hosting.Lifetime[14]
2023-05-02 13:19:29       Now listening on: http://[::]:80
2023-05-02 13:19:29 info: Microsoft.Hosting.Lifetime[0]
2023-05-02 13:19:29       Application started. Press Ctrl+C to shut down.
2023-05-02 13:19:29 info: Microsoft.Hosting.Lifetime[0]
2023-05-02 13:19:29       Hosting environment: Development
2023-05-02 13:19:29 info: Microsoft.Hosting.Lifetime[0]
2023-05-02 13:19:29       Content root path: /app/

问题原因及解决方案

1. Angular构建产物未被正确打包进容器

你的Dockerfile仅执行了dotnet publish,但ASP.NET Core不会自动构建Angular项目。需要在发布阶段添加Angular的构建步骤,将静态产物输出到ASP.NET Core的wwwroot目录。

修改Dockerfile的publish阶段:

FROM build AS publish
# 安装Node.js环境用于构建Angular
RUN apt-get update && apt-get install -y nodejs npm
# 切换到Angular项目根目录
WORKDIR "/src/FrontEnds/ShopFrontSpa/Client"
# 安装依赖
RUN npm install
# 构建Angular项目,输出到上级目录的wwwroot
RUN npm run build -- --output-path ../wwwroot
# 返回ASP.NET项目目录完成发布
WORKDIR "/src/FrontEnds/ShopFrontSpa"
RUN dotnet publish "ShopFrontSpa.csproj" -c Release -o /app/publish /p:UseAppHost=false

2. 开发环境下容器内尝试启动ng serve失败

Program.cs中,开发环境会调用spa.UseAngularCliServer启动ng serve,但容器的base镜像(aspnet:6.0)不含Node.js环境,且ng serve默认绑定localhost,容器外部无法访问。

解决方式:

  • 推荐采用静态文件托管(即上面修改Dockerfile的方式),同时可以删除Program.cs中开发环境启动ng serve的逻辑,或在Docker部署时设置环境为Production;
  • 如果非要在容器内用ng serve,需在镜像中安装Node.js,且修改Angular的start命令添加--host 0.0.0.0(不推荐,性能差且不符合Docker部署最佳实践)。

3. 静态文件目录检查

进入容器确认wwwroot目录是否存在Angular构建产物:

docker exec -it lost_chapters_shop_front ls /app/wwwroot

如果目录为空,说明Angular构建步骤有问题,检查npm依赖安装、构建命令是否执行成功。

4. PathBase配置影响

如果配置了PATH_BASE环境变量,访问URL需要包含对应路径;如果不需要,可直接删除这部分配置。

5. 端口与网络验证

  • 检查本地5110/7110端口是否被占用;
  • 进入容器内部直接访问服务,确认服务本身是否正常:
docker exec -it lost_chapters_shop_front curl http://localhost:80

如果能返回index.html内容,说明端口映射或本地网络(防火墙、代理)有问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:07:51