全栈项目容器化实战:从 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 食谱"吧!

相关推荐
万敏5 小时前
Vue3 全栈实战第七周:错误处理与请求层封装实战记录
vue.js·node.js·全栈
GitLqr20 小时前
Flutter 实战:使用 local_auth 实现生物识别(指纹/Face ID)
安全·flutter·全栈
Liora_Yvonne1 天前
不懂后端,只会 TypeScript,想独立做完整项目?这套全栈底座就是给前端准备的
前端·后端·全栈
GitLqr2 天前
Flutter + Unity 混合开发:用 unity_kit 实现高效的双向通信
flutter·unity3d·全栈
西安小哥2 天前
从 Vue 到万物:AI 加速下的前端开发者全栈进化论【第二课】
全栈
西安小哥2 天前
从 Vue 到万物:AI 加速下的前端开发者全栈进化论【第一课】
全栈
西安小哥2 天前
从 Vue 到万物:AI 加速下的前端开发者全栈进化论【第三课】
全栈
西安小哥2 天前
从 Vue 到万物:AI 加速下的前端开发者全栈进化论【第五课】
全栈
西安小哥2 天前
从 Vue 到万物:AI 加速下的前端开发者全栈进化论【第四课】
全栈