全栈项目容器化实战:从 React + NestJS 到 Docker 部署与跨域处理

本文将带你将一个使用 React + Zustand 作为前端、NestJS 作为后端的全栈项目,通过 Docker 容器化,并解决开发与生产环境中的跨域问题,让你轻松掌握项目打包发布的标准化流程。

1. 项目结构与前端跨域解决方案

项目根目录包含前端 todos 和后端 todos-backend 两个子项目。前端使用 Vite 构建,采用 Zustand 管理状态。

跨域问题与解决思路

由于浏览器同源策略,前端(开发端口 5173)直接请求后端(端口 3000)会报跨域错误。解决方案通常有两种:

  • 开发环境代理 :在 vite.config.ts 中配置代理,将 /api 请求转发到后端服务。
  • 生产环境 CORS:后端 NestJS 开启 CORS,允许指定域名或全部来源。

前端请求封装与拦截器

request.ts 中创建 Axios 实例,统一设置 baseURL/api,并利用请求拦截器注入 Token,响应拦截器统一处理数据与错误。

typescript

javascript 复制代码
// src/api/request.ts
import axios from 'axios';

const service = axios.create({
  baseURL: '/api', // 配合 Nginx 或开发代理
  timeout: 10000,
});

// 请求拦截:注入 token
service.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('token');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => Promise.reject(error)
);

// 响应拦截:直接返回 data,并全局捕获异常
service.interceptors.response.use(
  (response) => response.data,
  (error) => {
    console.error('API Error:', error.message);
    // 可在此处统一处理 401 跳转登录等
    return Promise.reject(error);
  }
);

export default service;

2. 后端 NestJS 跨域配置与接口开发

NestJS 后端在 main.ts 中启用 CORS,确保生产环境前端可正常请求接口。

typescript

javascript 复制代码
// src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // 开启跨域,根据实际部署环境限制 origin
  app.enableCors({
    origin: '*', // 生产环境建议替换为具体域名
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
    credentials: true,
  });
  await app.listen(process.env.PORT ?? 3000);
}
bootstrap();

同时,后端编写简单的 Todo 相关接口(示例略),并导出 API 供前端调用。

3. 前端状态管理(Zustand)与异步操作

使用 Zustand 创建 TodoStore,集中管理待办列表数据及操作。

typescript

typescript 复制代码
// src/store/todoStore.ts
import { create } from 'zustand';
import { type Todo } from '../types/todo';
import { fetchTodos as getTodos, createTodo } from '../api/todos';

interface TodoStore {
  todos: Todo[];
  fetchTodos: () => Promise<void>;
  addTodo: (title: string) => Promise<void>;
}

export const useTodoStore = create<TodoStore>((set, get) => ({
  todos: [],
  fetchTodos: async () => {
    const res = await getTodos();
    set({ todos: res.data }); // 注意:后端返回结构需规范
  },
  addTodo: async (title: string) => {
    const res = await createTodo(title);
    set((state) => ({ todos: [...state.todos, res.data] }));
  },
}));

在前端组件 TodoList.tsx 中,调用 Store 中的方法发起请求,实现页面交互。

tsx

javascript 复制代码
// src/components/TodoList.tsx
import React, { useEffect } from 'react';
import { useTodoStore } from '../store/todoStore';

const TodoList: React.FC = () => {
  const { todos, fetchTodos, addTodo } = useTodoStore();

  useEffect(() => {
    fetchTodos();
  }, []);

  const handleAdd = () => {
    const title = prompt('Enter todo title:');
    if (title) addTodo(title);
  };

  return (
    <div>
      <h1>Todo List</h1>
      <button onClick={handleAdd}>Add Todo</button>
      <ul>
        {todos.map((todo) => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
    </div>
  );
};

export default TodoList;

4. Docker 容器化配置与镜像构建

Dockerfile 好比一份"标准操作手册",通过指令描述应用环境,确保在任何机器上运行结果一致。

前端 Dockerfile

dockerfile

sql 复制代码
# 前端 Dockerfile 示例
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 使用 nginx 提供静态文件服务(生产推荐)
FROM nginx:alpine
COPY --from=0 /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

后端 Dockerfile

dockerfile

sql 复制代码
# 后端 Dockerfile 示例
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["node", "dist/main.js"]

构建与运行

bash

yaml 复制代码
# 构建镜像
docker build -t todos-frontend .
docker build -t todos-backend .

# 运行容器(可通过 docker-compose 统一编排)
docker run -p 80:80 todos-frontend
docker run -p 3000:3000 todos-backend

实际项目中,通常使用 docker-compose.yml 将前后端、数据库、Nginx 等统一编排,实现一键部署。

5. 总结

通过本文的实践,你将掌握:

  • 如何通过代理和 CORS 解决全栈项目跨域问题;
  • 使用 Zustand 结合 Axios 进行高效状态管理与请求封装;
  • 编写 Dockerfile 将前后端项目容器化,实现标准化部署。

容器化是现代应用交付的基石,结合 CI/CD 流程,可以极大提升开发与运维效率。快去为你的项目写一份"Dockerfile 食谱"吧!

相关推荐
SL_staff14 小时前
战略落地的最后一公里:从目标到个人日历的自动化链路实现
java·github·全栈
Ticnix15 小时前
RAG 的坑不在检索,在"对齐":pgvector 实战手记
python·agent·全栈
EatFan1 天前
多租户系统到底怎么设计?从 tenant_id 到 JWT 租户隔离的真实实践
前端·后端·全栈·多租户
EatFan1 天前
我为什么把患者与病例从 1:1 改成 1:N?一次真实数据库模型重构记录
数据库·后端·重构·健康医疗·全栈
狼爷1 天前
硅谷爆火的FDE是AI新风口,还是高级外包?
后端·全栈
狂师2 天前
最近火爆出圈的,FDE 到底是个什么岗位?
人工智能·程序员·全栈
万敏5 天前
Vue3 全栈实战:第一阶段复盘(第1-8周)
vue.js·node.js·全栈
先吃饱再说6 天前
从本地跑通到公网访问:前后端项目部署实战
运维·全栈