Nuxt/Vue应用部署GitHub Pages与Route53异常求助
问题描述
- 已解决GitHub Pages默认显示README的问题,当前可正常展示index文件,但Express服务器接口返回404,该情况切换GitHub Actions工作流后出现。
- 部署的是包含客户端与Express服务端代码的Nuxt Vue应用,本地运行完全正常,但部署至Route53时出现502 Bad Gateway错误。10个月前曾成功部署到GitHub Pages和Route53,现在无法正常运行,寻求排查建议。
相关配置文件
GitHub Actions工作流
# Sample workflow for building and deploying a Nuxt site to GitHub Pages # # To get started with Nuxt see: https://nuxtjs.org/docs/get-started/installation # name: Deploy Nuxt site to Pages on: # Runs on pushes targeting the default branch push: branches: ["main"] # Allows you to run this workflow manually from the Actions tab workflow_dispatch: # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages permissions: contents: read pages: write id-token: write # Allow one concurrent deployment concurrency: group: "pages" cancel-in-progress: true jobs: # Build job build: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Detect package manager id: detect-package-manager run: | if [ -f "${{ github.workspace }}/yarn.lock" ]; then echo "manager=yarn" >> $GITHUB_OUTPUT echo "command=install" >> $GITHUB_OUTPUT exit 0 elif [ -f "${{ github.workspace }}/package.json" ]; then echo "manager=npm" >> $GITHUB_OUTPUT echo "command=ci" >> $GITHUB_OUTPUT exit 0 else echo "Unable to determine packager manager" exit 1 fi - name: Setup Node uses: actions/setup-node@v3 with: node-version: "16" cache: ${{ steps.detect-package-manager.outputs.manager }} - name: Setup Pages uses: actions/configure-pages@v2 with: # Automatically inject router.base in your Nuxt configuration file and set # target to static (https://nuxtjs.org/docs/configuration-glossary/configuration-target/). # # You may remove this line if you want to manage the configuration yourself. static_site_generator: nuxt - name: Restore cache uses: actions/cache@v3 with: path: | dist .nuxt key: ${{ runner.os }}-nuxt-build-${{ hashFiles('dist') }} restore-keys: | ${{ runner.os }}-nuxt-build- - name: Install dependencies run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }} - name: Static HTML export with Nuxt run: ${{ steps.detect-package-manager.outputs.manager }} run generate - name: Upload artifact uses: actions/upload-pages-artifact@v1 with: path: ./dist # Deployment job deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest needs: build steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v1
package.json脚本
"scripts": { "dev": "cross-env NODE_ENV=development nodemon server/index.js --watch server", "build": "nuxt --openssl-legacy-provider build", "generate": "nuxt generate", "start": "cross-env NODE_ENV=production node server/index.js", },
server/index.js
if (process.env.NODE_ENV !== 'production') { require('dotenv').config(); } const Post = require('./models/post'); const express = require('express'); const consola = require('consola'); const { Nuxt, Builder } = require('nuxt'); const app = express(); const mongoose = require('mongoose'); const xss = require('xss-clean'); app.use( express.urlencoded({ extended: true }) ) app.use(express.json()) app.use(xss()); // Import and set Nuxt.js options const config = require('../nuxt.config.js'); config.dev = process.env.NODE_ENV !== 'production'; // Init Nuxt.js const nuxt = new Nuxt(config); const { host, port } = nuxt.options.server; const username = process.env.username; const pwd = process.env.pwd; const server = process.env.server; const db = process.env.db; const dbURI = `mongodb+srv://${username}:${pwd}@${server}/${db}?retryWrites=true&w=majority`; async function start() { // Build only in dev mode if (config.dev) { const builder = new Builder(nuxt); await builder.build(); } else { await nuxt.ready(); } // Render every route with Nuxt.js app.use(nuxt.render); consola.ready({ message: `Server listening on http://${host}:${port}`, badge: true }); } start(); mongoose .connect(dbURI, {useNewUrlParser: true, useUnifiedTopology: true}) .then((result) => { app.listen(port, host); // listen } ) .catch(err => console.log(err)); app.get('/isAlive', async (req, res) => { res.send('i am alive'); }); app.get('/posts', (req, res) => { Post .find() .sort({createdAt: -1}) .then((result) => { res.send(result); }) .catch((err) => console.log(err)); }) app.post( '/posts', (req, res) => { const post = new Post({ body: req.body.post.trim() }); post .save() .then((result) => { res.send(result); }) .catch((err) => console.log(err)); } );
nuxt.config.js
// import colors from 'vuetify/es5/util/colors' module.exports = { // Disable server-side rendering: https://go.nuxtjs.dev/ssr-mode ssr: false, telemetry: false, // Target: https://go.nuxtjs.dev/config-target target: 'static', // Global page headers: https://go.nuxtjs.dev/config-head head: { titleTemplate: '%s', title: '', htmlAttrs: { lang: 'en' }, meta: [ { charset: 'utf-8' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' }, { hid: 'description', name: 'description', content: '' } ], link: [ { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' } ] }, // Global CSS: https://go.nuxtjs.dev/config-css css: [ ], // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins plugins: [ ], // Auto import components: https://go.nuxtjs.dev/config-components components: true, // Modules for dev and build (recommended): https://go.nuxtjs.dev/config-modules buildModules: [ // https://go.nuxtjs.dev/typescript '@nuxtjs/typescript-build', // https://go.nuxtjs.dev/vuetify '@nuxtjs/vuetify', ], // Modules: https://go.nuxtjs.dev/config-modules modules: ['@nuxtjs/axios' ], axios: { baseURL: '/' }, // Vuetify module configuration: https://go.nuxtjs.dev/config-vuetify vuetify: { customVariables: ['~/assets/variables.scss'], theme: { dark: false } }, // Build Configuration: https://go.nuxtjs.dev/config-build build: { loaders: { vue: { transformAssetUrls: { audio: 'src' } } }, extend(config, ctx) { config.module.rules.push({ test: /\.(ogg|mp3|wav|mpe?g)$/i, loader: 'file-loader', options: { name: '[path][name].[ext]', esModule: false } }) } } }
补充说明
推送至main分支会触发构建,此前曾提交.nuxt与dist文件夹,但部署后仍出现上述问题。
排查建议
针对GitHub Pages接口404问题
- GitHub Pages仅支持静态文件托管,无法运行Node.js/Express服务。当前工作流用
nuxt generate生成静态文件部署,而你的Express接口属于服务端代码,静态环境不会启动这些接口,这是核心原因。之前成功部署可能是用了支持Node服务的平台,或是当时工作流并非仅部署静态文件。 - 调整接口部署方式:将Express后端迁移到独立的服务托管平台(如Vercel、AWS EC2/Elastic Beanstalk等),修改前端axios的
baseURL指向新的后端地址,确保前端请求能正确到达运行中的服务。
针对Route53 502 Bad Gateway问题
- 检查Route53解析配置:确认域名解析的目标地址是否正确,是否指向了运行后端服务的实例/负载均衡器。如果之前是静态前端+独立后端的部署模式,需确认后端服务是否正常运行。
- 后端服务状态排查:
- 若后端部署在AWS,检查EC2实例是否正常启动,安全组是否开放了服务端口(默认是nuxt配置的端口),是否能通过公网IP直接访问接口。
- 查看后端服务日志,排查是否存在环境变量缺失、依赖安装失败、MongoDB连接错误等导致服务启动失败的问题。
- 工作流完整性检查:当前GitHub Actions仅处理了前端静态文件的部署,未涉及后端服务的部署。如果之前的部署是同时更新前后端,需调整工作流或单独部署后端服务,确保Route53指向的后端是最新且运行正常的版本。
- Nuxt配置适配:你的nuxt.config.js设置了
ssr: false和target: 'static',属于纯静态模式,但代码中包含Express服务逻辑。若需要运行后端接口,应将ssr设为true、target设为server,并部署到支持Node服务的平台,而非GitHub Pages。 - 数据库连接验证:确认生产环境的MongoDB连接参数(环境变量)是否正确配置,后端服务是否有权限访问MongoDB集群,数据库连接失败会导致服务无法正常启动,进而引发502错误。
内容的提问来源于stack exchange,提问作者fumeng
相关产品推荐
相关产品推荐

