PAYATHON 2026

GitHub Actions 部署 Angular 18 后为何出现 404?

排障赵师傅

结论

404 是上传目录选错导致的。日志中已经给出了首页的实际位置:

dist/webapp/browser/index.html

但 workflow 上传的是整个 ./dist/,所以 GitHub Pages 部署包的根目录结构如下:

webapp/
└── browser/
    └── index.html

Pages 会在部署包根目录查找 index.html。由于根目录下没有这个文件,访问 https://mr-olufsen.github.io/webapp/ 时就会返回 404。

把上传路径改为:

path: ./dist/webapp/browser

这个项目部署在带有 /webapp/ 前缀的 URL 下,构建时还要设置:

ng build --base-href /webapp/

缺少这项配置时,即使首页可以打开,JS、CSS 等静态资源也可能从域名根目录加载,从而出现资源 404。

为什么 workflow 成功,页面却仍然 404

actions/deploy-pages 显示成功,只代表 artifact 已经上传并交给 GitHub Pages。它不会检查部署包根目录是否包含 index.html。

日志里的两段信息足以定位问题:

Output location: /home/runner/work/webapp/webapp/dist/webapp

以及:

./webapp/browser/index.html

上传 ./dist/ 后,index.html 在部署包内仍然隔着 webapp/browser/ 两层目录。GitHub Pages 不会自动进入这个子目录寻找首页。

Angular 18 使用 application builder 时,浏览器端文件通常生成在 dist/<project-name>/browser/。具体位置要以构建日志和 angular.json 中的 outputPath 为准,不能默认产物就在 dist/ 根目录。

推荐修改

下面沿用原 workflow 中的 action 主版本,只修改与这次故障有关的配置:

name: Deploy Angular to GitHub Pages

on:
  push:
    branches:
      - main
  workflow_dispatch:

permissions:
  contents: read
  pages: write
  id-token: write

concurrency:
  group: pages
  cancel-in-progress: true

jobs:
  build:
    runs-on: ubuntu-latest

    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}

    steps:
      - name: Checkout code
        uses: actions/checkout@v3

      - name: Use Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18.x
          cache: npm
          cache-dependency-path: package-lock.json

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build -- --base-href /webapp/

      - name: Setup Pages
        uses: actions/configure-pages@v3

      - name: Upload Pages artifact
        uses: actions/upload-pages-artifact@v2
        with:
          path: ./dist/webapp/browser

      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v2

如果仓库名称不是 webapp,需要分别修改以下两处:

run: npm run build -- --base-href /实际仓库名/
path: ./dist/实际项目输出目录/browser

base-href 对应 GitHub Pages URL 中的仓库路径,artifact 路径则对应 Angular 的实际输出目录。两者经常同名,但并不要求一致。

也可以在 angular.json 中固定 baseHref

如果项目始终部署在 /webapp/ 下,可以把配置写进 angular.json,然后在 workflow 中使用普通的构建命令:

{
  "projects": {
    "webapp": {
      "architect": {
        "build": {
          "configurations": {
            "production": {
              "baseHref": "/webapp/"
            }
          }
        }
      }
    }
  }
}

构建命令为:

npm run build

这样可以避免某个 workflow 遗漏 --base-href。如果应用还要部署到域名根目录或其他子路径,使用命令行参数会更灵活。

部署前检查产物

可以在上传 artifact 前加入检查步骤,确认上传目录内直接包含首页:

- name: Verify build output
  run: |
    test -f ./dist/webapp/browser/index.html
    ls -la ./dist/webapp/browser

需要检查的是:

./dist/webapp/browser/index.html

不是:

./dist/index.html

上传 ./dist/webapp/browser 后,artifact 根目录应类似:

index.html
main-*.js
polyfills-*.js
styles-*.css
favicon.ico

如果 index.html 仍在 webapp/browser/ 这样的子目录里,说明上传路径还没有指向静态站点的根目录。

如果只有刷新子路由时出现 404

如果首页已经可以打开,但直接访问或刷新下面这样的 Angular 路由仍然返回 404:

https://mr-olufsen.github.io/webapp/settings

原因与首页 404 不同。GitHub Pages 是静态文件服务,不会像应用服务器一样把任意路径回退到 index.html。

一种处理方法是使用 hash 路由,将地址改为:

https://mr-olufsen.github.io/webapp/#/settings

Angular 路由可以这样配置:

provideRouter(routes, withHashLocation())

另一种方法是在构建后把 index.html 复制为 404.html:

- name: Build
  run: |
    npm run build -- --base-href /webapp/
    cp ./dist/webapp/browser/index.html ./dist/webapp/browser/404.html

是否采用 404.html,要根据项目的路由、重定向和搜索引擎收录要求决定。如果只要求在纯静态托管环境中可靠运行,hash 路由通常更直接。

还需要确认的 Pages 设置

在仓库的 Settings > Pages 中,部署来源应选择 GitHub Actions。如果 Pages 使用分支发布模式,即使 workflow 完成了 artifact 部署流程,仓库实际展示的内容也可能来自其他来源。

原 workflow 还监听了 pull_request。正式站点通常只需在代码推送到 main 时部署,同时保留手动触发,避免多个提交或拉取请求争用同一个 Pages 环境。

action 版本可以根据仓库当前支持情况另行升级,但这不是本次 404 的原因。日志已经表明 artifact 上传和部署均已成功。

备注:内容仅供参考。