Skip to content

网络请求调试 - React应用HTTP调试完全指南

1. 浏览器开发者工具

1.1 Network面板基础

typescript
const networkPanel = {
  基本功能: {
    请求列表: '显示所有HTTP请求',
    请求详情: '查看请求头、响应头、payload',
    时间线: '请求时序图',
    过滤器: '按类型、域名、状态码过滤',
    搜索: '搜索请求内容'
  },
  
  请求信息: {
    General: '请求方法、状态码、URL',
    Headers: '请求头和响应头',
    Payload: '请求体',
    Preview: '响应预览',
    Response: '原始响应',
    Timing: '请求各阶段耗时'
  },
  
  快捷操作: {
    清空: 'Ctrl + E',
    保存HAR: '导出网络日志',
    过滤: '按类型/域名过滤',
    复制: '复制为cURL/Fetch'
  }
};

1.2 查看请求详情

typescript
// 典型的API请求分析
const requestAnalysis = {
  基本信息: {
    URL: 'https://api.example.com/users/123',
    Method: 'GET',
    Status: '200 OK',
    Type: 'xhr',
    Size: '2.1 KB',
    Time: '125 ms'
  },
  
  请求头: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer token...',
    'Accept': 'application/json',
    'User-Agent': 'Mozilla/5.0...'
  },
  
  响应头: {
    'Content-Type': 'application/json',
    'Cache-Control': 'max-age=3600',
    'Access-Control-Allow-Origin': '*',
    'X-Response-Time': '15ms'
  },
  
  响应体: {
    id: 123,
    name: 'John Doe',
    email: 'john@example.com'
  }
};

2. React中的网络请求调试

2.1 Fetch API调试

typescript
// 在组件中调试fetch请求
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    async function fetchUser() {
      try {
        console.log('🔍 Fetching user:', userId);
        
        // 在Network面板查看此请求
        const response = await fetch(`/api/users/${userId}`);
        
        console.log('📥 Response status:', response.status);
        console.log('📥 Response headers:', [...response.headers]);
        
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        
        const data = await response.json();
        console.log('✅ Data received:', data);
        
        setUser(data);
      } catch (err) {
        console.error('❌ Fetch error:', err);
        setError(err.message);
      } finally {
        setLoading(false);
      }
    }
    
    fetchUser();
  }, [userId]);
  
  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error}</div>;
  if (!user) return <div>No user found</div>;
  
  return (
    <div>
      <h1>{user.name}</h1>
      <p>{user.email}</p>
    </div>
  );
}

2.2 Axios调试

typescript
import axios from 'axios';

// 配置Axios拦截器用于调试
const setupAxiosDebug = () => {
  // 请求拦截器
  axios.interceptors.request.use(
    config => {
      console.group('🚀 Axios Request');
      console.log('URL:', config.url);
      console.log('Method:', config.method);
      console.log('Headers:', config.headers);
      console.log('Data:', config.data);
      console.log('Params:', config.params);
      console.groupEnd();
      
      // 可以在这里修改请求
      config.metadata = { startTime: new Date() };
      
      return config;
    },
    error => {
      console.error('❌ Request Error:', error);
      return Promise.reject(error);
    }
  );
  
  // 响应拦截器
  axios.interceptors.response.use(
    response => {
      const endTime = new Date();
      const duration = endTime - response.config.metadata.startTime;
      
      console.group('✅ Axios Response');
      console.log('URL:', response.config.url);
      console.log('Status:', response.status);
      console.log('Duration:', `${duration}ms`);
      console.log('Headers:', response.headers);
      console.log('Data:', response.data);
      console.groupEnd();
      
      return response;
    },
    error => {
      console.group('❌ Axios Error');
      console.log('URL:', error.config?.url);
      console.log('Status:', error.response?.status);
      console.log('Message:', error.message);
      console.log('Response:', error.response?.data);
      console.groupEnd();
      
      return Promise.reject(error);
    }
  );
};

// 使用
setupAxiosDebug();

// 组件中使用
function DataFetcher() {
  const [data, setData] = useState(null);
  
  useEffect(() => {
    axios.get('/api/data')
      .then(response => {
        setData(response.data);
      })
      .catch(error => {
        console.error('Failed to fetch:', error);
      });
  }, []);
  
  return <div>{data && JSON.stringify(data)}</div>;
}

2.3 React Query调试

typescript
import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';

// 配置QueryClient用于调试
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      // 开发环境启用详细日志
      onError: (error) => {
        console.error('Query Error:', error);
      },
      onSuccess: (data) => {
        console.log('Query Success:', data);
      },
      // 启用重试日志
      retry: (failureCount, error) => {
        console.log(`Retry attempt ${failureCount}:`, error);
        return failureCount < 3;
      }
    }
  },
  // 配置logger
  logger: {
    log: (...args) => console.log('[React Query]', ...args),
    warn: (...args) => console.warn('[React Query]', ...args),
    error: (...args) => console.error('[React Query]', ...args)
  }
});

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <YourApp />
      {/* React Query开发工具 */}
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}

// 使用useQuery
function Users() {
  const { data, isLoading, error, refetch } = useQuery({
    queryKey: ['users'],
    queryFn: async () => {
      console.log('🔄 Fetching users...');
      const response = await fetch('/api/users');
      
      if (!response.ok) {
        console.error('❌ Response not ok:', response.status);
        throw new Error('Failed to fetch users');
      }
      
      const data = await response.json();
      console.log('✅ Users fetched:', data.length, 'users');
      
      return data;
    },
    // 启用详细日志
    meta: {
      errorMessage: 'Failed to load users'
    }
  });
  
  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  
  return (
    <div>
      <button onClick={() => refetch()}>Refresh</button>
      <ul>
        {data.map(user => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </div>
  );
}

3. 网络请求Mock

3.1 MSW (Mock Service Worker)

typescript
// src/mocks/handlers.ts
import { rest } from 'msw';

export const handlers = [
  // GET请求mock
  rest.get('/api/users', (req, res, ctx) => {
    console.log('🎭 MSW: Intercepted GET /api/users');
    
    return res(
      ctx.status(200),
      ctx.json([
        { id: 1, name: 'John' },
        { id: 2, name: 'Jane' }
      ])
    );
  }),
  
  // POST请求mock
  rest.post('/api/users', async (req, res, ctx) => {
    const body = await req.json();
    console.log('🎭 MSW: Intercepted POST /api/users', body);
    
    return res(
      ctx.status(201),
      ctx.json({
        id: 3,
        ...body
      })
    );
  }),
  
  // 模拟错误
  rest.get('/api/error', (req, res, ctx) => {
    console.log('🎭 MSW: Simulating error');
    
    return res(
      ctx.status(500),
      ctx.json({
        error: 'Internal Server Error'
      })
    );
  }),
  
  // 模拟延迟
  rest.get('/api/slow', (req, res, ctx) => {
    console.log('🎭 MSW: Simulating slow response');
    
    return res(
      ctx.delay(3000),  // 3秒延迟
      ctx.json({ message: 'Slow response' })
    );
  })
];

// src/mocks/browser.ts
import { setupWorker } from 'msw';
import { handlers } from './handlers';

export const worker = setupWorker(...handlers);

// src/index.tsx
if (process.env.NODE_ENV === 'development') {
  const { worker } = await import('./mocks/browser');
  worker.start({
    onUnhandledRequest: 'warn'  // 警告未处理的请求
  });
}

3.2 自定义Mock工具

typescript
// mockApi.ts
class MockAPI {
  private mocks = new Map();
  private delays = new Map();
  
  // 注册mock响应
  mock(url, response, options = {}) {
    console.log(`📝 Mocking: ${url}`);
    
    this.mocks.set(url, {
      response,
      status: options.status || 200,
      delay: options.delay || 0
    });
  }
  
  // 拦截fetch
  setupFetchMock() {
    const originalFetch = window.fetch;
    
    window.fetch = async (url, options) => {
      const urlString = typeof url === 'string' ? url : url.toString();
      
      // 检查是否有mock
      if (this.mocks.has(urlString)) {
        const mock = this.mocks.get(urlString);
        
        console.group('🎭 Mock Response');
        console.log('URL:', urlString);
        console.log('Method:', options?.method || 'GET');
        console.log('Delay:', mock.delay, 'ms');
        console.log('Response:', mock.response);
        console.groupEnd();
        
        // 模拟延迟
        if (mock.delay > 0) {
          await new Promise(resolve => setTimeout(resolve, mock.delay));
        }
        
        // 返回mock响应
        return Promise.resolve({
          ok: mock.status >= 200 && mock.status < 300,
          status: mock.status,
          json: async () => mock.response,
          text: async () => JSON.stringify(mock.response),
          headers: new Headers({
            'Content-Type': 'application/json'
          })
        });
      }
      
      // 没有mock,使用真实请求
      console.log('🌐 Real fetch:', urlString);
      return originalFetch(url, options);
    };
  }
  
  // 清除所有mock
  clearAll() {
    console.log('🧹 Clearing all mocks');
    this.mocks.clear();
  }
}

// 使用
const mockAPI = new MockAPI();
mockAPI.setupFetchMock();

// 注册mock
mockAPI.mock('/api/users', [
  { id: 1, name: 'John' },
  { id: 2, name: 'Jane' }
], { delay: 500 });

mockAPI.mock('/api/error', 
  { error: 'Not found' },
  { status: 404 }
);

4. 代理配置

4.1 Vite代理配置

javascript
// vite.config.js
export default {
  server: {
    proxy: {
      // 代理所有/api请求
      '/api': {
        target: 'http://localhost:3001',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, ''),
        // 配置代理日志
        configure: (proxy, options) => {
          proxy.on('error', (err, req, res) => {
            console.log('❌ Proxy error:', err);
          });
          proxy.on('proxyReq', (proxyReq, req, res) => {
            console.log('🔄 Proxying:', req.method, req.url);
          });
          proxy.on('proxyRes', (proxyRes, req, res) => {
            console.log('✅ Proxy response:', proxyRes.statusCode, req.url);
          });
        }
      },
      
      // WebSocket代理
      '/ws': {
        target: 'ws://localhost:3001',
        ws: true
      }
    }
  }
};

4.2 Next.js代理配置

javascript
// next.config.js
module.exports = {
  async rewrites() {
    return [
      {
        source: '/api/:path*',
        destination: 'http://localhost:3001/:path*'
      }
    ];
  }
};

4.3 CRA代理配置

javascript
// src/setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:3001',
      changeOrigin: true,
      pathRewrite: {
        '^/api': ''
      },
      onProxyReq: (proxyReq, req, res) => {
        console.log('🔄 Proxying:', req.method, req.url);
      },
      onProxyRes: (proxyRes, req, res) => {
        console.log('✅ Proxy response:', proxyRes.statusCode);
      },
      onError: (err, req, res) => {
        console.error('❌ Proxy error:', err);
      }
    })
  );
};

5. 请求性能分析

5.1 Timing分析

typescript
// 详细的请求时序分析
const requestTiming = {
  Queueing: '请求在队列中等待的时间',
  Stalled: '在发送前的停滞时间',
  DNSLookup: 'DNS查询时间',
  InitialConnection: '建立TCP连接时间',
  SSL: 'SSL握手时间',
  RequestSent: '发送请求时间',
  WaitingTTFB: '等待首字节响应时间',
  ContentDownload: '下载响应内容时间'
};

// 使用Performance API测量
function measureRequest(url) {
  const startTime = performance.now();
  
  fetch(url)
    .then(response => {
      const endTime = performance.now();
      const duration = endTime - startTime;
      
      console.group('⏱️ Request Performance');
      console.log('URL:', url);
      console.log('Total Time:', `${duration.toFixed(2)}ms`);
      console.log('Status:', response.status);
      console.log('Size:', response.headers.get('content-length'), 'bytes');
      console.groupEnd();
      
      return response.json();
    });
}

// 使用Resource Timing API
function analyzeResourceTiming(url) {
  const entries = performance.getEntriesByType('resource');
  const entry = entries.find(e => e.name.includes(url));
  
  if (entry) {
    console.group('📊 Resource Timing');
    console.log('DNS Lookup:', `${entry.domainLookupEnd - entry.domainLookupStart}ms`);
    console.log('TCP Connect:', `${entry.connectEnd - entry.connectStart}ms`);
    console.log('Request:', `${entry.responseStart - entry.requestStart}ms`);
    console.log('Response:', `${entry.responseEnd - entry.responseStart}ms`);
    console.log('Total:', `${entry.duration}ms`);
    console.groupEnd();
  }
}

5.2 请求缓存分析

typescript
// 分析缓存命中情况
function analyzeCaching() {
  const entries = performance.getEntriesByType('resource');
  
  const cacheStats = {
    fromCache: 0,
    fromNetwork: 0,
    total: entries.length
  };
  
  entries.forEach(entry => {
    // 检查是否从缓存加载
    if (entry.transferSize === 0) {
      cacheStats.fromCache++;
      console.log('💾 From cache:', entry.name);
    } else {
      cacheStats.fromNetwork++;
      console.log('🌐 From network:', entry.name, `(${entry.transferSize} bytes)`);
    }
  });
  
  console.group('📈 Cache Statistics');
  console.log('Total Requests:', cacheStats.total);
  console.log('From Cache:', cacheStats.fromCache);
  console.log('From Network:', cacheStats.fromNetwork);
  console.log('Cache Hit Rate:', `${(cacheStats.fromCache / cacheStats.total * 100).toFixed(2)}%`);
  console.groupEnd();
}

6. WebSocket调试

6.1 WebSocket连接调试

typescript
class DebugWebSocket extends WebSocket {
  constructor(url, protocols) {
    super(url, protocols);
    
    console.log('🔌 WebSocket: Connecting to', url);
    
    this.addEventListener('open', (event) => {
      console.log('✅ WebSocket: Connected');
    });
    
    this.addEventListener('message', (event) => {
      console.group('📨 WebSocket: Message Received');
      console.log('Data:', event.data);
      console.log('Time:', new Date().toISOString());
      try {
        const parsed = JSON.parse(event.data);
        console.log('Parsed:', parsed);
      } catch (e) {
        // 不是JSON数据
      }
      console.groupEnd();
    });
    
    this.addEventListener('error', (event) => {
      console.error('❌ WebSocket: Error', event);
    });
    
    this.addEventListener('close', (event) => {
      console.log('🔌 WebSocket: Closed', {
        code: event.code,
        reason: event.reason,
        wasClean: event.wasClean
      });
    });
  }
  
  send(data) {
    console.group('📤 WebSocket: Sending');
    console.log('Data:', data);
    try {
      const parsed = JSON.parse(data);
      console.log('Parsed:', parsed);
    } catch (e) {
      // 不是JSON数据
    }
    console.groupEnd();
    
    super.send(data);
  }
}

// 使用
function ChatComponent() {
  const [ws, setWs] = useState(null);
  const [messages, setMessages] = useState([]);
  
  useEffect(() => {
    const socket = new DebugWebSocket('ws://localhost:8080');
    
    socket.onmessage = (event) => {
      const message = JSON.parse(event.data);
      setMessages(prev => [...prev, message]);
    };
    
    setWs(socket);
    
    return () => {
      socket.close();
    };
  }, []);
  
  const sendMessage = (text) => {
    if (ws && ws.readyState === WebSocket.OPEN) {
      ws.send(JSON.stringify({ type: 'message', text }));
    }
  };
  
  return (
    <div>
      {messages.map((msg, i) => (
        <div key={i}>{msg.text}</div>
      ))}
      <button onClick={() => sendMessage('Hello')}>Send</button>
    </div>
  );
}

6.2 Socket.io调试

typescript
import io from 'socket.io-client';

// 启用调试模式
const socket = io('http://localhost:3001', {
  // 启用日志
  debug: true,
  // 自定义日志函数
  logger: {
    log: (...args) => console.log('[Socket.io]', ...args),
    error: (...args) => console.error('[Socket.io]', ...args)
  }
});

// 监听所有事件
function logAllEvents(socket) {
  const onevent = socket.onevent;
  
  socket.onevent = function(packet) {
    console.group('📡 Socket.io Event');
    console.log('Event:', packet.data[0]);
    console.log('Data:', packet.data.slice(1));
    console.log('Time:', new Date().toISOString());
    console.groupEnd();
    
    onevent.call(this, packet);
  };
}

logAllEvents(socket);

// 监听连接事件
socket.on('connect', () => {
  console.log('✅ Socket.io: Connected', socket.id);
});

socket.on('disconnect', (reason) => {
  console.log('🔌 Socket.io: Disconnected', reason);
});

socket.on('error', (error) => {
  console.error('❌ Socket.io: Error', error);
});

7. GraphQL请求调试

7.1 Apollo Client调试

typescript
import { ApolloClient, InMemoryCache, ApolloLink } from '@apollo/client';

// 创建日志链接
const logLink = new ApolloLink((operation, forward) => {
  console.group('🚀 GraphQL Request');
  console.log('Operation:', operation.operationName);
  console.log('Variables:', operation.variables);
  console.log('Query:', operation.query.loc.source.body);
  console.groupEnd();
  
  const startTime = Date.now();
  
  return forward(operation).map(response => {
    const duration = Date.now() - startTime;
    
    console.group('✅ GraphQL Response');
    console.log('Operation:', operation.operationName);
    console.log('Duration:', `${duration}ms`);
    console.log('Data:', response.data);
    if (response.errors) {
      console.error('Errors:', response.errors);
    }
    console.groupEnd();
    
    return response;
  });
});

// 创建Apollo Client
const client = new ApolloClient({
  uri: '/graphql',
  cache: new InMemoryCache(),
  link: logLink.concat(httpLink),
  // 开发工具
  connectToDevTools: true
});

// 使用
function Users() {
  const { data, loading, error } = useQuery(GET_USERS);
  
  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  
  return (
    <ul>
      {data.users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

7.2 GraphQL Playground

typescript
// 在开发环境启用GraphQL Playground
const enableGraphQLPlayground = () => {
  if (process.env.NODE_ENV === 'development') {
    console.log('🎮 GraphQL Playground available at /graphql');
  }
};

8. 错误处理和调试

8.1 网络错误处理

typescript
// 统一错误处理
async function fetchWithErrorHandling(url, options = {}) {
  try {
    console.log('🔄 Fetching:', url);
    
    const response = await fetch(url, options);
    
    // 检查HTTP状态
    if (!response.ok) {
      const error = new Error(`HTTP ${response.status}: ${response.statusText}`);
      error.response = response;
      error.status = response.status;
      
      // 尝试解析错误响应
      try {
        error.data = await response.json();
      } catch (e) {
        error.data = await response.text();
      }
      
      console.error('❌ HTTP Error:', {
        url,
        status: error.status,
        data: error.data
      });
      
      throw error;
    }
    
    const data = await response.json();
    console.log('✅ Success:', url, data);
    
    return data;
  } catch (error) {
    // 网络错误
    if (error.name === 'TypeError' && error.message.includes('fetch')) {
      console.error('❌ Network Error:', {
        url,
        message: 'Network request failed',
        originalError: error
      });
      
      error.isNetworkError = true;
    }
    
    // 超时错误
    if (error.name === 'AbortError') {
      console.error('⏱️ Timeout Error:', url);
      error.isTimeout = true;
    }
    
    throw error;
  }
}

// 使用
function DataFetcher() {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  
  useEffect(() => {
    fetchWithErrorHandling('/api/data')
      .then(setData)
      .catch(error => {
        setError(error);
        
        // 根据错误类型显示不同信息
        if (error.isNetworkError) {
          alert('网络连接失败,请检查网络');
        } else if (error.isTimeout) {
          alert('请求超时,请稍后重试');
        } else if (error.status === 404) {
          alert('资源不存在');
        } else if (error.status >= 500) {
          alert('服务器错误,请稍后重试');
        }
      });
  }, []);
  
  if (error) return <div>Error: {error.message}</div>;
  if (!data) return <div>Loading...</div>;
  
  return <div>{JSON.stringify(data)}</div>;
}

8.2 重试机制

typescript
// 带重试的fetch
async function fetchWithRetry(url, options = {}, maxRetries = 3) {
  let lastError;
  
  for (let i = 0; i <= maxRetries; i++) {
    try {
      if (i > 0) {
        console.log(`🔄 Retry attempt ${i}/${maxRetries}:`, url);
        // 指数退避
        await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
      }
      
      const response = await fetch(url, options);
      
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}`);
      }
      
      return await response.json();
    } catch (error) {
      lastError = error;
      console.error(`❌ Attempt ${i + 1} failed:`, error.message);
      
      // 最后一次尝试失败,抛出错误
      if (i === maxRetries) {
        console.error(`❌ All ${maxRetries + 1} attempts failed`);
        throw lastError;
      }
    }
  }
}

// 使用
function RobustDataFetcher() {
  const [data, setData] = useState(null);
  
  useEffect(() => {
    fetchWithRetry('/api/data', {}, 3)
      .then(setData)
      .catch(error => {
        console.error('Final error:', error);
      });
  }, []);
  
  return data ? <div>{JSON.stringify(data)}</div> : <div>Loading...</div>;
}

9. 调试工具推荐

9.1 浏览器扩展

typescript
const browserExtensions = {
  通用工具: [
    'React Developer Tools - 查看组件树和props',
    'Redux DevTools - Redux状态管理调试',
    'Apollo Client Devtools - GraphQL调试'
  ],
  
  网络工具: [
    'ModHeader - 修改请求头',
    'Requestly - 拦截和修改请求',
    'JSON Formatter - 格式化JSON响应'
  ],
  
  性能工具: [
    'Lighthouse - 性能分析',
    'Web Vitals - 核心指标监控'
  ]
};

9.2 独立工具

typescript
const standaloneTools = {
  Postman: {
    功能: ['API测试', '请求集合', '环境变量', '自动化测试'],
    优势: '功能强大,团队协作'
  },
  
  Insomnia: {
    功能: ['REST API', 'GraphQL', 'gRPC', 'WebSocket'],
    优势: '简洁易用,支持多种协议'
  },
  
  Charles: {
    功能: ['代理调试', 'SSL抓包', '请求修改', '限速模拟'],
    优势: '专业的网络调试工具'
  },
  
  Fiddler: {
    功能: ['HTTP调试', '性能分析', '安全测试'],
    优势: 'Windows平台首选'
  }
};

10. 调试最佳实践

10.1 调试检查清单

typescript
const debuggingChecklist = [
  '✅ 检查请求URL是否正确',
  '✅ 检查请求方法(GET/POST等)',
  '✅ 检查请求头(Content-Type, Authorization等)',
  '✅ 检查请求体格式',
  '✅ 检查响应状态码',
  '✅ 检查响应头(CORS等)',
  '✅ 检查响应数据格式',
  '✅ 检查网络连接',
  '✅ 检查代理配置',
  '✅ 检查HTTPS证书',
  '✅ 检查请求超时',
  '✅ 检查并发请求数',
  '✅ 检查缓存策略',
  '✅ 检查错误处理'
];

10.2 性能优化建议

typescript
const performanceOptimization = {
  减少请求数: [
    '合并API请求',
    '使用GraphQL',
    '批量操作',
    '按需加载'
  ],
  
  优化请求大小: [
    '启用gzip压缩',
    '只请求需要的字段',
    '分页加载',
    '图片压缩'
  ],
  
  利用缓存: [
    'HTTP缓存头',
    'Service Worker',
    '本地存储',
    'CDN缓存'
  ],
  
  并发控制: [
    '限制并发数',
    '请求队列',
    '请求优先级',
    '取消重复请求'
  ]
};

11. 总结

网络请求调试的核心要点:

  1. 浏览器开发者工具: Network面板是最基础的调试工具
  2. 请求拦截: 使用拦截器记录和修改请求
  3. Mock数据: 使用MSW等工具模拟API
  4. 代理配置: 解决跨域和环境切换问题
  5. 性能分析: 关注请求时序和缓存
  6. 错误处理: 完善的错误处理和重试机制
  7. 调试工具: 善用浏览器扩展和独立工具
  8. 最佳实践: 遵循调试检查清单

掌握这些网络请求调试技巧,可以快速定位和解决网络相关问题,提升开发效率。