从单体到微服务:Ant Design Pro实现前后端分离的架构演进指南

从单体到微服务:Ant Design Pro实现前后端分离的架构演进指南

【免费下载链接】ant-design-pro 👨🏻‍💻👩🏻‍💻 Use Ant Design like a Pro! 【免费下载链接】ant-design-pro 项目地址: https://gitcode.com/gh_mirrors/an/ant-design-pro

引言:前后端分离的痛点与解决方案

你是否正面临这些挑战:前端团队等待后端接口阻塞开发进度?不同微服务接口风格混乱导致维护成本激增?跨团队协作时API文档与实际实现不一致?本文将系统讲解如何基于Ant Design Pro实现与微服务架构的无缝集成,通过15个实战案例、7个架构图和9个对比表格,帮助你构建高扩展性的企业级应用。

读完本文你将掌握:

  • Ant Design Pro与微服务通信的5种模式及适用场景
  • 基于Umi请求中间件的API网关适配方案
  • 多环境代理配置与服务发现的最佳实践
  • 权限控制在前后端分离架构中的完整实现
  • 微前端与微服务结合的部署策略

一、Ant Design Pro与微服务架构的协同基础

1.1 架构概览:前后端分离的核心组件

Ant Design Pro作为企业级前端框架,通过分层设计完美适配微服务架构:

mermaid

Ant Design Pro的核心优势在于:

  • 内置的Umi请求库支持拦截器、错误处理和请求缓存
  • ProComponents组件库提供开箱即用的数据展示和表单处理
  • 完善的权限管理系统可与微服务的认证授权机制无缝对接
  • 多环境配置支持开发、测试和生产环境的平滑切换

1.2 前后端通信模型对比

通信模式实现方式优势劣势适用场景
直接通信前端直连微服务架构简单,无中间层损耗跨域问题,认证复杂,服务地址暴露内部系统,微服务数量少
API网关通过网关转发请求统一入口,集中认证,协议转换单点故障风险,性能瓶颈多客户端,复杂认证
BFF层后端For前端服务适配前端需求,数据聚合增加系统复杂度,开发成本复杂数据展示,多端适配
GraphQL声明式数据查询按需获取数据,减少请求次数学习曲线,缓存复杂数据需求多变的场景
WebSocket双向实时通信低延迟,实时更新连接管理复杂,服务器压力实时监控,协作工具

在Ant Design Pro中,推荐采用"API网关+部分BFF"的混合架构,通过Umi的request配置实现灵活的服务通信策略。

二、API请求层设计:微服务通信的实现

2.1 Umi Request核心配置与拦截器应用

Ant Design Pro基于Umi的request模块实现与后端服务的通信,典型配置如下:

// src/app.tsx
import { request } from 'umi';
import { message } from 'antd';
import { getToken, refreshToken } from '@/utils/auth';

// 请求拦截器
request.interceptors.request.use((url, options) => {
  // 添加认证令牌
  const token = getToken();
  return {
    url,
    options: {
      ...options,
      headers: {
        ...options.headers,
        Authorization: token ? `Bearer ${token}` : undefined,
      },
    },
  };
});

// 响应拦截器
request.interceptors.response.use(async (response, options) => {
  const { data } = response;
  
  // 处理401错误(令牌过期)
  if (data.code === 401) {
    const newToken = await refreshToken();
    if (newToken) {
      // 重试原请求
      return request(url, {
        ...options,
        headers: {
          ...options.headers,
          Authorization: `Bearer ${newToken}`,
        },
      });
    }
  }
  
  // 统一错误处理
  if (data.code !== 200) {
    message.error(data.message || '操作失败');
    return Promise.reject(data);
  }
  
  return data;
});

拦截器的主要应用场景:

  • 请求拦截:添加认证信息、设置超时时间、数据转换
  • 响应拦截:统一错误处理、令牌刷新、数据格式化
  • 缓存控制:对GET请求实现本地缓存,减少重复请求

2.2 微服务API的模块化封装

推荐按业务领域划分API服务模块,保持代码组织清晰:

// src/services/user.ts - 用户服务
import { request } from '@umijs/max';

export async function getUserList(params) {
  return request<API.UserList>('/api/users', {
    method: 'GET',
    params,
  });
}

export async function getUserDetail(id) {
  return request<API.UserDetail>(`/api/users/${id}`, {
    method: 'GET',
  });
}

// src/services/order.ts - 订单服务
import { request } from '@umijs/max';

export async function createOrder(data) {
  return request<API.OrderResult>('/api/orders', {
    method: 'POST',
    data,
  });
}

export async function getOrderList(params) {
  return request<API.OrderList>('/api/orders', {
    method: 'GET',
    params,
  });
}

这种模块化设计带来的好处:

  • 职责明确,便于维护
  • 类型定义集中管理
  • 便于模拟数据和单元测试
  • 支持按需加载,优化性能

2.3 多服务并发请求与数据聚合

在复杂页面中经常需要同时请求多个微服务接口,可使用Promise.all结合useRequest实现:

// src/pages/Dashboard/index.tsx
import { useRequest } from '@umijs/max';
import { getUserStats } from '@/services/user';
import { getOrderStats } from '@/services/order';
import { getProductStats } from '@/services/product';

const Dashboard = () => {
  // 并行请求多个微服务数据
  const { data: userStats } = useRequest(getUserStats);
  const { data: orderStats } = useRequest(getOrderStats);
  const { data: productStats } = useRequest(getProductStats);
  
  // 组合数据
  const totalStats = useMemo(() => {
    if (userStats && orderStats && productStats) {
      return {
        totalUsers: userStats.total,
        totalOrders: orderStats.total,
        totalProducts: productStats.total,
        revenue: orderStats.revenue,
      };
    }
    return null;
  }, [userStats, orderStats, productStats]);
  
  return (
    <div>
      {totalStats && (
        <StatisticCardGroup>
          <StatisticCard title="总用户数" value={totalStats.totalUsers} />
          <StatisticCard title="总订单数" value={totalStats.totalOrders} />
          <StatisticCard title="产品总数" value={totalStats.totalProducts} />
          <StatisticCard title="总收入" value={totalStats.revenue} prefix="¥" />
        </StatisticCardGroup>
      )}
    </div>
  );
};

对于更复杂的数据聚合场景,推荐在BFF层实现,前端只需调用一个聚合接口。

三、代理配置与服务发现:连接微服务的桥梁

3.1 开发环境代理配置详解

Ant Design Pro通过Umi的代理配置解决开发环境的跨域问题,典型配置如下:

// config/proxy.ts
export default {
  dev: {
    // 用户服务代理
    '/api/users/': {
      target: 'http://user-service:8080',
      changeOrigin: true,
      pathRewrite: { '^/api/users/': '/' },
    },
    // 订单服务代理
    '/api/orders/': {
      target: 'http://order-service:8080',
      changeOrigin: true,
      pathRewrite: { '^/api/orders/': '/' },
    },
    // 产品服务代理
    '/api/products/': {
      target: 'http://product-service:8080',
      changeOrigin: true,
      pathRewrite: { '^/api/products/': '/' },
    },
    // 统一API网关
    '/api/gateway/': {
      target: 'http://api-gateway:8080',
      changeOrigin: true,
      pathRewrite: { '^/api/gateway/': '/' },
    },
  },
  test: {
    '/api/': {
      target: 'https://test-api-gateway.example.com',
      changeOrigin: true,
      pathRewrite: { '^': '' },
    },
  },
  pre: {
    '/api/': {
      target: 'https://pre-api-gateway.example.com',
      changeOrigin: true,
      pathRewrite: { '^': '' },
    },
  },
};

多服务代理的优势:

  • 开发环境无需CORS配置
  • 前端可直接使用服务名访问
  • 不同环境配置隔离
  • 支持WebSocket代理

3.2 生产环境的服务发现策略

在生产环境中,推荐使用以下几种服务发现方案:

  1. API网关模式:所有请求通过统一网关路由
// src/utils/request.ts
const baseUrl = process.env.NODE_ENV === 'production' 
  ? 'https://api-gateway.example.com' 
  : '';

export const request = createRequest({
  prefix: baseUrl,
  timeout: 10000,
});
  1. 配置中心动态获取:通过配置中心获取服务地址
// src/services/config.ts
export async function getServiceEndpoints() {
  return request('/api/config/service-endpoints');
}

// src/app.tsx
export async function getInitialState() {
  // 从配置中心获取服务地址
  const serviceEndpoints = await getServiceEndpoints();
  
  // 动态配置请求前缀
  request.config.prefix = serviceEndpoints.gateway;
  
  return {
    serviceEndpoints,
  };
}
  1. DNS服务发现:结合云服务提供商的DNS解析
// 根据环境变量动态选择服务域名
const serviceDomain = process.env.NODE_ENV === 'production' 
  ? 'service.example.com' 
  : 'service-dev.example.com';

export const userService = {
  getUser: (id) => request(`http://user.${serviceDomain}/users/${id}`),
};

服务发现方案对比:

方案实现复杂度灵活性运维成本适用场景
API网关大多数企业应用
配置中心最高大规模微服务集群
DNS解析云原生应用,简单场景
静态配置最低最低最低小型应用,固定环境

四、权限控制:微服务架构下的安全策略

4.1 基于RBAC的权限模型实现

Ant Design Pro的权限系统可与微服务的RBAC模型无缝集成:

// src/access.ts
export default function access(initialState: { currentUser?: API.CurrentUser }) {
  const { currentUser } = initialState || {};
  
  return {
    // 基于角色的权限判断
    canReadUsers: currentUser?.roles?.includes('admin') || 
                  currentUser?.roles?.includes('user-manager'),
    canEditUsers: currentUser?.roles?.includes('admin'),
    canDeleteUsers: currentUser?.roles?.includes('admin'),
    
    // 基于权限码的判断
    canApproveOrders: currentUser?.permissions?.includes('order:approve'),
    canExportReports: currentUser?.permissions?.includes('report:export'),
    
    // 数据权限过滤
    canAccessDepartmentData: (departmentId) => 
      currentUser?.departmentId === departmentId || 
      currentUser?.roles?.includes('admin'),
  };
}

在路由配置中应用权限控制:

// config/routes.ts
export default [
  {
    path: '/users',
    name: '用户管理',
    component: './users',
    access: 'canReadUsers', // 关联access.ts中的权限定义
    routes: [
      {
        path: '/users/create',
        name: '创建用户',
        component: './users/create',
        access: 'canEditUsers', // 更严格的权限控制
      },
    ],
  },
];

4.2 接口级别的权限控制

除了页面级权限,还需要对API请求进行权限控制:

// src/services/user.ts
import { request } from '@umijs/max';
import { getAccess } from '@umijs/max';

export async function deleteUser(id) {
  // 前端权限检查
  const access = getAccess();
  if (!access.canDeleteUsers) {
    throw new Error('没有删除用户的权限');
  }
  
  // 调用微服务API
  return request(`/api/users/${id}`, {
    method: 'DELETE',
  });
}

更细粒度的控制可以在请求拦截器中实现:

// src/utils/request.ts
request.interceptors.request.use((url, options) => {
  const access = getAccess();
  
  // 检查是否有访问该API的权限
  const requiredPermission = getRequiredPermission(url, options.method);
  if (requiredPermission && !access[requiredPermission]) {
    return Promise.reject(new Error(`没有权限访问: ${requiredPermission}`));
  }
  
  return { url, options };
});

4.3 微服务间的认证与授权

在前后端分离架构中,推荐使用JWT实现跨服务认证:

// src/utils/auth.ts
import { message } from 'antd';
import { history } from 'umi';

// 获取存储的令牌
export function getToken() {
  return localStorage.getItem('token');
}

// 设置令牌
export function setToken(token) {
  localStorage.setItem('token', token);
}

// 清除令牌
export function clearToken() {
  localStorage.removeItem('token');
}

// 刷新令牌
export async function refreshToken() {
  try {
    const response = await request('/api/auth/refresh', {
      method: 'POST',
      data: {
        refreshToken: localStorage.getItem('refreshToken'),
      },
    });
    
    setToken(response.token);
    localStorage.setItem('refreshToken', response.refreshToken);
    return response.token;
  } catch (error) {
    // 刷新失败,需要重新登录
    clearToken();
    localStorage.removeItem('refreshToken');
    message.error('登录已过期,请重新登录');
    history.push('/user/login');
    return null;
  }
}

JWT在微服务架构中的优势:

  • 无状态,减轻认证服务压力
  • 跨服务共享认证信息
  • 减少服务间调用的认证开销
  • 支持细粒度的权限声明

五、ProComponents与微服务数据交互

5.1 ProTable与微服务API的无缝对接

ProTable组件支持直接对接微服务API,自动处理分页、排序和筛选:

// src/pages/order/list.tsx
import { ProTable } from '@ant-design/pro-components';
import { getOrderList, deleteOrder } from '@/services/order';

const OrderList = () => {
  const columns = [
    {
      title: '订单编号',
      dataIndex: 'orderNo',
      key: 'orderNo',
      search: false,
    },
    {
      title: '客户名称',
      dataIndex: 'customerName',
      key: 'customerName',
      search: {
        show: true,
      },
    },
    {
      title: '订单金额',
      dataIndex: 'amount',
      key: 'amount',
      valueType: 'money',
      sorter: true,
    },
    {
      title: '订单状态',
      dataIndex: 'status',
      key: 'status',
      valueType: 'select',
      valueEnum: {
        PENDING: { text: '待处理', status: 'processing' },
        CONFIRMED: { text: '已确认', status: 'success' },
        CANCELLED: { text: '已取消', status: 'error' },
      },
      search: {
        show: true,
        itemRender: (searchConfig, props, dom) => [dom],
      },
    },
    {
      title: '创建时间',
      dataIndex: 'createdAt',
      key: 'createdAt',
      valueType: 'dateTime',
      sorter: true,
    },
    {
      title: '操作',
      key: 'action',
      valueType: 'option',
      render: (_, record) => [
        <a key="detail" onClick={() => handleViewDetail(record.id)}>查看</a>,
        <a key="edit" onClick={() => handleEdit(record.id)}>编辑</a>,
        <a key="delete" onClick={() => handleDelete(record.id)}>删除</a>,
      ],
    },
  ];
  
  return (
    <ProTable<API.OrderItem>
      headerTitle="订单管理"
      rowKey="id"
      request={async (params) => {
        // 转换ProTable参数为微服务API所需格式
        const result = await getOrderList({
          page: params.current,
          size: params.pageSize,
          sort: params.sortField ? `${params.sortField},${params.sortOrder === 'ascend' ? 'asc' : 'desc'}` : undefined,
          ...params,
        });
        
        // 转换微服务响应为ProTable所需格式
        return {
          data: result.items,
          total: result.total,
          success: true,
        };
      }}
      columns={columns}
      pagination={{
        pageSize: 10,
        showSizeChanger: true,
        showQuickJumper: true,
      }}
    />
  );
};

ProTable的高级特性:

  • 自动处理加载状态
  • 内置搜索和筛选功能
  • 支持自定义请求和响应转换
  • 批量操作和行操作支持
  • 可编辑表格功能

5.2 表单与多服务数据交互

ProForm组件支持复杂表单场景,结合多个微服务的数据:

// src/pages/order/create.tsx
import { ProForm, ProFormSelect, ProFormDatePicker } from '@ant-design/pro-components';
import { useRequest } from '@umijs/max';
import { createOrder } from '@/services/order';
import { getProductList } from '@/services/product';
import { getCustomerList } from '@/services/customer';

const OrderCreate = () => {
  // 获取产品列表(产品服务)
  const { data: products } = useRequest(() => getProductList({ pageSize: 100 }));
  
  // 获取客户列表(客户服务)
  const { data: customers } = useRequest(() => getCustomerList({ pageSize: 100 }));
  
  return (
    <ProForm<API.OrderForm>
      title="创建订单"
      layout="horizontal"
      onFinish={async (values) => {
        try {
          await createOrder(values);
          message.success('订单创建成功');
          history.push('/orders');
        } catch (error) {
          message.error('订单创建失败');
        }
      }}
    >
      <ProFormSelect
        name="customerId"
        label="客户选择"
        options={customers?.items.map(item => ({
          label: item.name,
          value: item.id,
        })) || []}
        rules={[{ required: true, message: '请选择客户' }]}
        request={async (params) => {
          // 远程搜索客户
          const result = await getCustomerList({ 
            keyword: params.keyword,
            pageSize: 20 
          });
          return {
            options: result.items.map(item => ({
              label: item.name,
              value: item.id,
            })),
          };
        }}
        fieldProps={{
          showSearch: true,
          placeholder: '搜索客户',
        }}
      />
      
      <ProFormDatePicker
        name="orderDate"
        label="订单日期"
        rules={[{ required: true, message: '请选择订单日期' }]}
      />
      
      <ProForm.List<API.OrderItem>
        name="items"
        label="订单明细"
        rules={[{ required: true, message: '请添加订单明细' }]}
        initialValue={[{ productId: '', quantity: 1, price: 0 }]}
      >
        {(fields, { add, remove }) => (
          <>
            {fields.map((field, index) => (
              <div key={field.key} className="order-item-row">
                <ProFormSelect
                  {...field}
                  name={`${field.name}.productId`}
                  label={`产品 ${index + 1}`}
                  options={products?.items.map(item => ({
                    label: item.name,
                    value: item.id,
                  })) || []}
                  rules={[{ required: true, message: '请选择产品' }]}
                />
                <ProFormDigit
                  {...field}
                  name={`${field.name}.quantity`}
                  label="数量"
                  min={1}
                  rules={[{ required: true }]}
                />
                <ProFormDigit
                  {...field}
                  name={`${field.name}.price`}
                  label="单价"
                  min={0}
                  rules={[{ required: true }]}
                />
                <Button 
                  type="text" 
                  danger 
                  onClick={() => remove(field.name)}
                >
                  删除
                </Button>
              </div>
            ))}
            <Button type="dashed" onClick={() => add()}>
              添加产品
            </Button>
          </>
        )}
      </ProForm.List>
      
      <ProFormText
        name="notes"
        label="备注"
        fieldProps={{
          rows: 4,
        }}
      />
    </ProForm>
  );
};

5.3 状态管理与缓存策略

在复杂应用中,推荐使用Redux或Umi的useModel进行全局状态管理:

// src/models/cart.ts
import { Effect, Reducer } from 'umi';
import { addToCart, removeFromCart, getCart } from '@/services/cart';

export interface CartItem {
  productId: string;
  name: string;
  price: number;
  quantity: number;
}

export interface CartModelState {
  items: CartItem[];
  total: number;
  loading: boolean;
}

export interface CartModelType {
  namespace: 'cart';
  state: CartModelState;
  effects: {
    fetch: Effect;
    add: Effect;
    remove: Effect;
  };
  reducers: {
    save: Reducer<CartModelState>;
    updateLoading: Reducer<CartModelState>;
  };
}

const CartModel: CartModelType = {
  namespace: 'cart',
  state: {
    items: [],
    total: 0,
    loading: false,
  },
  effects: {
    *fetch(_, { call, put }) {
      yield put({ type: 'updateLoading', payload: true });
      const response = yield call(getCart);
      yield put({
        type: 'save',
        payload: {
          items: response.items,
          total: response.total,
        },
      });
      yield put({ type: 'updateLoading', payload: false });
    },
    *add({ payload }, { call, put, select }) {
      yield put({ type: 'updateLoading', payload: true });
      yield call(addToCart, payload);
      // 重新获取购物车
      yield put({ type: 'fetch' });
    },
    *remove({ payload }, { call, put }) {
      yield put({ type: 'updateLoading', payload: true });
      yield call(removeFromCart, payload);
      // 重新获取购物车
      yield put({ type: 'fetch' });
    },
  },
  reducers: {
    save(state, action) {
      return {
        ...state,
        ...action.payload,
      };
    },
    updateLoading(state, action) {
      return {
        ...state,
        loading: action.payload,
      };
    },
  },
};

export default CartModel;

使用缓存策略减少对微服务的请求:

// src/services/product.ts
import { request } from '@umijs/max';
import { useCache } from '@/hooks/useCache';

// 使用缓存获取产品分类
export function useProductCategories() {
  const { getCache, setCache } = useCache();
  const cacheKey = 'product:categories';
  
  return useRequest(async () => {
    // 先从缓存获取
    const cached = getCache(cacheKey);
    if (cached) {
      return cached;
    }
    
    // 缓存不存在,从API获取
    const response = await request('/api/products/categories');
    
    // 设置缓存,有效期1小时
    setCache(cacheKey, response, 3600000);
    
    return response;
  }, {
    refreshDeps: [], // 不自动刷新
  });
}

六、实战案例:构建完整的微服务前端应用

6.1 用户服务集成:认证与个人信息管理

用户服务是微服务架构中的基础服务,实现登录流程:

// src/pages/user/login/index.tsx
import { ProForm } from '@ant-design/pro-components';
import { useRequest } from '@umijs/max';
import { message } from 'antd';
import { history } from 'umi';
import { login } from '@/services/user';
import { setToken, setRefreshToken } from '@/utils/auth';

const LoginPage = () => {
  const handleSubmit = async (values) => {
    try {
      const response = await login(values);
      
      // 存储令牌
      setToken(response.token);
      setRefreshToken(response.refreshToken);
      
      // 获取用户信息(会触发权限重新计算)
      const { initialState, setInitialState } = getDvaApp()._store;
      const currentUser = await initialState.fetchUserInfo();
      setInitialState({
        ...initialState,
        currentUser,
      });
      
      message.success('登录成功');
      history.push('/dashboard');
    } catch (error) {
      message.error('用户名或密码错误');
    }
  };
  
  return (
    <div className="login-container">
      <div className="login-form-card">
        <ProForm
          onFinish={handleSubmit}
          layout="vertical"
          submitter={{
            searchConfig: {
              submitText: '登录',
            },
            render: (_, dom) => dom.pop(),
          }}
        >
          <ProFormText
            name="username"
            label="用户名"
            rules={[{ required: true, message: '请输入用户名' }]}
            placeholder="请输入用户名"
          />
          <ProFormPassword
            name="password"
            label="密码"
            rules={[{ required: true, message: '请输入密码' }]}
            placeholder="请输入密码"
          />
          <ProFormCheckbox name="remember" label="记住我" />
        </ProForm>
      </div>
    </div>
  );
};

6.2 订单服务集成:复杂表单与状态管理

订单服务通常涉及多步骤流程,使用状态管理维护流程状态:

// src/pages/order/create/stepForm.tsx
import { Steps, Card } from 'antd';
import { useState } from 'react';
import { useModel } from '@umijs/max';
import BasicInfoStep from './steps/BasicInfoStep';
import ProductSelectStep from './steps/ProductSelectStep';
import ConfirmStep from './steps/ConfirmStep';
import { createOrder } from '@/services/order';

const { Step } = Steps;

const OrderCreateStepForm = () => {
  const [current, setCurrent] = useState(0);
  const [formData, setFormData] = useState({
    customer: {},
    products: [],
    paymentMethod: 'online',
    notes: '',
  });
  
  const { initialState } = useModel('@@initialState');
  const currentUser = initialState.currentUser;
  
  const steps = [
    {
      title: '基本信息',
      content: <BasicInfoStep 
                 formData={formData} 
                 onChange={setFormData} 
               />,
    },
    {
      title: '产品选择',
      content: <ProductSelectStep 
                 formData={formData} 
                 onChange={setFormData} 
               />,
    },
    {
      title: '确认提交',
      content: <ConfirmStep formData={formData} />,
    },
  ];
  
  const next = () => {
    setCurrent(current + 1);
  };
  
  const prev = () => {
    setCurrent(current - 1);
  };
  
  const handleSubmit = async () => {
    try {
      // 转换表单数据为API请求格式
      const orderData = {
        customerId: formData.customer.id,
        items: formData.products.map(item => ({
          productId: item.id,
          quantity: item.quantity,
          price: item.price,
        })),
        paymentMethod: formData.paymentMethod,
        notes: formData.notes,
        createdBy: currentUser.id,
      };
      
      // 调用订单服务创建订单
      await createOrder(orderData);
      
      message.success('订单创建成功');
      history.push('/orders');
    } catch (error) {
      message.error('订单创建失败,请重试');
    }
  };
  
  return (
    <Card>
      <Steps current={current}>
        {steps.map((item) => (
          <Step key={item.title} title={item.title} />
        ))}
      </Steps>
      <div className="steps-content">{steps[current].content}</div>
      <div className="steps-action">
        {current > 0 && (
          <Button onClick={() => prev()}>
            上一步
          </Button>
        )}
        {current === steps.length - 1 ? (
          <Button type="primary" onClick={handleSubmit}>
            提交订单
          </Button>
        ) : (
          <Button type="primary" onClick={() => next()}>
            下一步
          </Button>
        )}
      </div>
    </Card>
  );
};

6.3 产品服务集成:数据展示与搜索功能

产品服务通常需要处理大量数据和复杂搜索,ProTable的高级应用:

// src/pages/product/list.tsx
import { ProTable, SearchSelect } from '@ant-design/pro-components';
import { useRequest } from '@umijs/max';
import { Button, Tag } from 'antd';
import { getProductList, updateProductStatus } from '@/services/product';
import { getCategoryList } from '@/services/category';

const ProductList = () => {
  // 获取产品分类(用于筛选)
  const { data: categories } = useRequest(getCategoryList);
  
  // 状态标签配置
  const statusMap = {
    active: { color: 'green', text: '在售' },
    inactive: { color: 'orange', text: '下架' },
    discontinued: { color: 'red', text: '停产' },
  };
  
  // 表格列定义
  const columns = [
    {
      title: '产品编码',
      dataIndex: 'code',
      key: 'code',
      search: {
        show: true,
      },
      width: 120,
    },
    {
      title: '产品名称',
      dataIndex: 'name',
      key: 'name',
      search: { show: true },
      ellipsis: true,
    },
    {
      title: '分类',
      dataIndex: 'categoryName',
      key: 'categoryName',
      filters: categories?.map(cat => ({
        text: cat.name,
        value: cat.id,
      })),
      onFilter: (value, record) => record.categoryId === value,
      search: {
        show: true,
        itemRender: () => (
          <SearchSelect
            placeholder="搜索分类"
            fetchSuggestions={async (keyword) => {
              const res = await getCategoryList({ keyword });
              return res.map(cat => ({
                label: cat.name,
                value: cat.id,
              }));
            }}
          />
        ),
      },
    },
    {
      title: '价格',
      dataIndex: 'price',
      key: 'price',
      valueType: 'money',
      sorter: true,
      search: {
        show: true,
        itemRender: () => (
          <RangePicker
            style={{ width: '100%' }}
            placeholder={['最低价格', '最高价格']}
          />
        ),
      },
    },
    {
      title: '库存',
      dataIndex: 'stock',
      key: 'stock',
      sorter: true,
      render: (stock) => {
        if (stock <= 10) {
          return <Tag color="red">{stock}</Tag>;
        } else if (stock <= 50) {
          return <Tag color="orange">{stock}</Tag>;
        }
        return <Tag color="green">{stock}</Tag>;
      },
    },
    {
      title: '状态',
      dataIndex: 'status',
      key: 'status',
      filters: Object.entries(statusMap).map(([value, { text }]) => ({
        text,
        value,
      })),
      render: (status) => {
        const { color, text } = statusMap[status] || { color: 'default', text: '未知' };
        return <Tag color={color}>{text}</Tag>;
      },
    },
    {
      title: '操作',
      key: 'action',
      valueType: 'option',
      render: (_, record) => [
        <a key="view" onClick={() => history.push(`/products/${record.id}`)}>查看</a>,
        <a key="edit" onClick={() => history.push(`/products/${record.id}/edit`)}>编辑</a>,
        <a 
          key="status" 
          onClick={() => handleStatusChange(record.id, record.status)}
        >
          {record.status === 'active' ? '下架' : '上架'}
        </a>,
      ],
    },
  ];
  
  return (
    <ProTable<API.ProductItem>
      headerTitle="产品管理"
      rowKey="id"
      request={async (params) => {
        // 处理价格范围搜索
        if (params.price) {
          params.minPrice = params.price[0];
          params.maxPrice = params.price[1];
          delete params.price;
        }
        
        // 调用产品服务API
        const result = await getProductList(params);
        
        return {
          data: result.items,
          total: result.total,
          success: true,
        };
      }}
      columns={columns}
      toolBarRender={() => [
        <Button 
          type="primary" 
          onClick={() => history.push('/products/create')}
        >
          新增产品
        </Button>,
      ]}
      pagination={{
        pageSize: 10,
        showSizeChanger: true,
        showQuickJumper: true,
      }}
      rowKey="id"
    />
  );
};

七、部署与监控:微服务架构的前端运维

7.1 构建优化与多环境部署

Ant Design Pro提供完善的构建配置,适配微服务架构的部署需求:

// config/config.ts
import { defineConfig } from 'umi';

export default defineConfig({
  // 构建配置
  mfsu: {}, // 模块化联邦构建
  dynamicImport: {
    loading: '@/loading',
  },
  // 环境变量配置
  define: {
    'process.env.API_GATEWAY': process.env.API_GATEWAY || '/api',
    'process.env.SENTRY_DSN': process.env.SENTRY_DSN || '',
  },
  // 路由配置
  routes: [
    // 路由定义...
  ],
  // 代理配置
  proxy: {
    // 代理配置...
  },
  // 其他配置...
});

多环境部署策略:

# package.json
{
  "scripts": {
    "build:dev": "cross-env API_GATEWAY=https://dev-api-gateway.example.com umi build",
    "build:test": "cross-env API_GATEWAY=https://test-api-gateway.example.com umi build",
    "build:prod": "cross-env API_GATEWAY=https://api-gateway.example.com umi build",
    "deploy:dev": "npm run build:dev && ./deploy.sh dev",
    "deploy:test": "npm run build:test && ./deploy.sh test",
    "deploy:prod": "npm run build:prod && ./deploy.sh prod"
  }
}

7.2 性能监控与错误追踪

集成Sentry进行前端错误监控:

// src/app.tsx
import * as Sentry from '@sentry/react';
import { Integrations } from '@sentry/tracing';

// 初始化Sentry
if (process.env.NODE_ENV === 'production' && process.env.SENTRY_DSN) {
  Sentry.init({
    dsn: process.env.SENTRY_DSN,
    integrations: [
      new Integrations.BrowserTracing(),
    ],
    tracesSampleRate: 0.5,
    // 添加用户上下文
    beforeSend: (event, hint) => {
      const { initialState } = getDvaApp()._store;
      if (initialState?.currentUser) {
        event.user = {
          id: initialState.currentUser.id,
          username: initialState.currentUser.username,
          email: initialState.currentUser.email,
        };
      }
      return event;
    },
  });
}

// 请求错误上报
request.interceptors.response.use(
  (response) => response,
  (error) => {
    // 上报API错误
    if (process.env.NODE_ENV === 'production' && process.env.SENTRY_DSN) {
      Sentry.captureException(error, {
        extra: {
          url: error.config.url,
          method: error.config.method,
          status: error.response?.status,
          data: error.config.data,
        },
      });
    }
    return Promise.reject(error);
  }
);

性能监控实现:

// src/utils/performance.ts
export function trackApiPerformance(url, method, duration, success) {
  // 可以发送到监控服务或日志服务
  if (window.performance && window.performance.mark) {
    // 使用Performance API标记
    performance.mark(`api-${url}-${method}-end`);
    performance.measure(
      `api-${url}-${method}`,
      `api-${url}-${method}-start`,
      `api-${url}-${method}-end`
    );
  }
  
  // 上报性能数据
  request('/api/monitor/performance', {
    method: 'POST',
    data: {
      type: 'api',
      url,
      method,
      duration,
      success,
      timestamp: new Date().getTime(),
      userAgent: navigator.userAgent,
      userId: getCurrentUserId(),
    },
    // 避免监控请求本身被监控
    skipErrorHandler: true,
  }).catch(() => {
    // 监控请求失败,不处理
  });
}

// 在请求拦截器中添加性能标记
request.interceptors.request.use((url, options) => {
  if (window.performance && window.performance.mark) {
    performance.mark(`api-${url}-${options.method}-start`);
  }
  
  const startTime = Date.now();
  
  // 在响应拦截器中计算耗时
  const originalThen = options.then;
  options.then = function(response) {
    const duration = Date.now() - startTime;
    trackApiPerformance(url, options.method, duration, true);
    return originalThen.call(this, response);
  };
  
  const originalCatch = options.catch;
  options.catch = function(error) {
    const duration = Date.now() - startTime;
    trackApiPerformance(url, options.method, duration, false);
    return originalCatch.call(this, error);
  };
  
  return { url, options };
});

八、总结与展望:前后端分离架构的演进方向

8.1 最佳实践总结

本文介绍的Ant Design Pro与微服务集成的核心要点:

  1. 分层架构设计

    • API层:统一封装微服务接口
    • 数据层:处理状态管理和缓存
    • UI层:使用ProComponents构建界面
    • 权限层:实现细粒度的访问控制
  2. 通信策略

    • 开发环境:使用代理解决跨域
    • 生产环境:通过API网关或服务发现
    • 认证机制:JWT实现跨服务认证
    • 数据聚合:简单场景前端聚合,复杂场景BFF层处理
  3. 性能优化

    • 请求优化:拦截器、缓存、并发控制
    • 构建优化:代码分割、懒加载、资源压缩
    • 监控优化:错误追踪、性能监控、用户行为分析

8.2 未来趋势与演进方向

  1. 微前端架构:将前端应用拆分为更小的微前端应用,每个微前端对应一个微服务领域

mermaid

  1. GraphQL网关:使用GraphQL统一API接口,解决前端数据聚合问题

  2. 实时通信:结合WebSocket或Server-Sent Events实现实时数据更新

  3. AI辅助开发:使用AI工具辅助生成API调用代码、表单验证规则等

结语

通过本文介绍的方法,你可以基于Ant Design Pro构建一个与微服务架构完美契合的前端应用。关键是要合理设计API请求层、权限控制和状态管理,同时结合ProComponents组件库提高开发效率。随着微服务架构的不断演进,前端架构也需要持续优化,以适应业务的变化和增长。

希望本文提供的实践指南能帮助你在实际项目中更好地实现前后端分离,构建高性能、高扩展性的企业级应用。如有任何问题或建议,欢迎在评论区留言讨论。

如果你觉得本文对你有帮助,请点赞、收藏并关注作者,获取更多前端架构实践指南!

【免费下载链接】ant-design-pro 👨🏻‍💻👩🏻‍💻 Use Ant Design like a Pro! 【免费下载链接】ant-design-pro 项目地址: https://gitcode.com/gh_mirrors/an/ant-design-pro

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值