Next.js在GitHub Actions构建失败:预渲染无法访问Django API
Next.js + Django Docker项目构建时API调用失败的解决方案
问题背景
采用Next.js(App Router)前端、Django API后端的Docker项目,本地双容器通信正常,但在GitHub Actions执行构建时,因未启动Django服务,预渲染页面时axios调用API失败导致构建终止。错误表现为getaddrinfo ENOTFOUND backend,根源是服务器组件在构建阶段发起了真实API请求。
解决方案
方案3:指定页面/组件跳过预渲染(推荐)
这是最轻量化的解决方式,针对单个页面或组件关闭预渲染,无需修改CI流程或引入额外依赖。
方法1:将ImageList改为客户端组件
在ImageList.tsx顶部添加'use client'指令,将API调用移至useEffect中(客户端组件仅在浏览器端运行,构建阶段不会执行):
'use client'; import axios from 'axios'; import { useEffect, useState } from 'react'; import Thumbnail from './Thumbnail'; import './ImageList.css'; interface Image { source: string, id: number }; export default function ImageList() { const [imageList, setImageList] = useState<Image[]>([]); useEffect(() => { const fetchImages = async () => { axios.defaults.baseURL = 'http://backend:8000'; const response = await axios.get('/api/image/'); setImageList(response.data); }; fetchImages(); }, []); return ( <div className='image-grid-container'> {imageList.map((image) => <Thumbnail src={image.source} id={image.id} key={image.id}/> )} </div> ); };
方法2:设置单个页面为动态渲染
若希望整个首页跳过预渲染,在app/page.tsx顶部添加动态配置:
// app/page.tsx export const dynamic = "force-dynamic"; import ImageList from './ImageList'; export default function Home() { return <ImageList />; }
该配置会让Next.js在每次请求时才渲染页面,构建阶段不会执行API调用。
方案1:在GitHub Actions中模拟后端API
使用Mock Service Worker(MSW)拦截构建阶段的API请求,返回模拟数据。
- 安装依赖:
npm install msw --save-dev
- 创建Mock处理器文件
mocks/handlers.ts:
import { http, HttpResponse } from 'msw'; export const handlers = [ http.get('http://backend:8000/api/image/', () => { return HttpResponse.json([ { source: '/mock-image-1.jpg', id: 1 }, { source: '/mock-image-2.jpg', id: 2 } ]); }), ];
- 创建Mock Provider组件
app/mock-provider.tsx:
'use client'; import { useEffect } from 'react'; import { setupWorker } from 'msw/browser'; import { handlers } from '../mocks/handlers'; const worker = setupWorker(...handlers); export function MockProvider({ children }: { children: React.ReactNode }) { useEffect(() => { // 仅在测试/构建环境启用Mock if (process.env.NODE_ENV !== 'production') { worker.start(); } }, []); return children; }
- 在根布局中引入Mock Provider:
// app/layout.tsx import { MockProvider } from './mock-provider'; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body> <MockProvider>{children}</MockProvider> </body> </html> ); }
- 在GitHub Actions构建步骤中启用Mock:
- name: Build Next.js app env: NODE_ENV: test run: npm run build
方案2:在GitHub Actions中启动双容器
利用Docker Compose在CI环境中启动后端服务,确保构建时API可访问。
- 确保项目根目录有
docker-compose.yml:
version: '3.8' services: backend: build: ./backend ports: - "8000:8000" # 后端启动命令、环境变量等配置 frontend: build: ./frontend depends_on: - backend # 前端配置
- 修改GitHub Actions workflow文件:
name: Build and Validate on: [push, pull_request] jobs: build: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Start backend service run: docker-compose up -d backend - name: Wait for backend to be ready run: | # 轮询直到后端API可访问 until curl -s --head --fail http://localhost:8000/api/image/; do sleep 3 done - name: Install frontend dependencies working-directory: ./frontend run: npm install - name: Build frontend working-directory: ./frontend run: npm run build - name: Clean up containers run: docker-compose down
方案4:关闭全局预渲染(非首选)
若所有页面都无需预渲染,可在根布局中设置全局动态配置:
// app/layout.tsx export const dynamic = "force-dynamic"; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body>{children}</body> </html> ); }
此方案会完全失去预渲染的性能优势,仅在特殊场景下使用。
内容的提问来源于stack exchange,提问作者cdyswnnr
相关产品推荐
相关产品推荐

