error-handling

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Error Handling

错误处理

Quick Start

快速开始

When handling errors:
  1. Never expose technical details to users
  2. Log errors server-side with context
  3. Provide user-friendly error messages
  4. Use appropriate HTTP status codes
  5. Implement error recovery when possible
处理错误时需遵循以下原则:
  1. 永远不要向用户暴露技术细节
  2. 在服务端记录带上下文的错误日志
  3. 提供对用户友好的错误提示
  4. 使用合适的HTTP状态码
  5. 尽可能实现错误恢复

Common Patterns

常见模式

API Error Handling

API错误处理

typescript
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  try {
    // Business logic
    const result = await processRequest();
    return NextResponse.json(result);
  } catch (error) {
    // Log error with context
    console.error('API Error:', {
      endpoint: '/api/example',
      error: error.message,
      stack: error.stack,
      timestamp: new Date().toISOString(),
    });
    
    // Return user-friendly error
    return NextResponse.json(
      { error: 'Ha ocurrido un error. Por favor, intenta nuevamente.' },
      { status: 500 }
    );
  }
}
typescript
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  try {
    // Business logic
    const result = await processRequest();
    return NextResponse.json(result);
  } catch (error) {
    // Log error with context
    console.error('API Error:', {
      endpoint: '/api/example',
      error: error.message,
      stack: error.stack,
      timestamp: new Date().toISOString(),
    });
    
    // Return user-friendly error
    return NextResponse.json(
      { error: 'Ha ocurrido un error. Por favor, intenta nuevamente.' },
      { status: 500 }
    );
  }
}

Validation Errors

验证错误

typescript
import { z } from 'zod';

const schema = z.object({
  email: z.string().email(),
  name: z.string().min(1),
});

try {
  const data = schema.parse(requestBody);
} catch (error) {
  if (error instanceof z.ZodError) {
    return NextResponse.json(
      { 
        error: 'Datos inválidos',
        details: error.errors.map(e => ({
          field: e.path.join('.'),
          message: e.message,
        }))
      },
      { status: 400 }
    );
  }
}
typescript
import { z } from 'zod';

const schema = z.object({
  email: z.string().email(),
  name: z.string().min(1),
});

try {
  const data = schema.parse(requestBody);
} catch (error) {
  if (error instanceof z.ZodError) {
    return NextResponse.json(
      { 
        error: 'Datos inválidos',
        details: error.errors.map(e => ({
          field: e.path.join('.'),
          message: e.message,
        }))
      },
      { status: 400 }
    );
  }
}

Component Error Handling

组件错误处理

typescript
'use client';

import { useState } from 'react';

function ProductCard({ product }: ProductCardProps) {
  const [error, setError] = useState<string | null>(null);
  
  const handleAddToCart = async () => {
    try {
      setError(null);
      await addToCart(product.id);
    } catch (error) {
      setError('No se pudo agregar el producto al carrito');
      console.error('Add to cart error:', error);
    }
  };
  
  return (
    <div>
      {error && (
        <div className="text-red-500 text-sm">{error}</div>
      )}
      <Button onClick={handleAddToCart}>Agregar</Button>
    </div>
  );
}
typescript
'use client';

import { useState } from 'react';

function ProductCard({ product }: ProductCardProps) {
  const [error, setError] = useState<string | null>(null);
  
  const handleAddToCart = async () => {
    try {
      setError(null);
      await addToCart(product.id);
    } catch (error) {
      setError('No se pudo agregar el producto al carrito');
      console.error('Add to cart error:', error);
    }
  };
  
  return (
    <div>
      {error && (
        <div className="text-red-500 text-sm">{error}</div>
      )}
      <Button onClick={handleAddToCart}>Agregar</Button>
    </div>
  );
}

Error Boundary

Error Boundary

typescript
'use client';

import { ErrorBoundary } from 'react-error-boundary';

function ErrorFallback({ error, resetErrorBoundary }) {
  return (
    <div role="alert" className="p-4 border border-red-300 rounded">
      <h2>Algo salió mal</h2>
      <p>{error.message}</p>
      <Button onClick={resetErrorBoundary}>Intentar de nuevo</Button>
    </div>
  );
}

function App() {
  return (
    <ErrorBoundary FallbackComponent={ErrorFallback}>
      <YourComponent />
    </ErrorBoundary>
  );
}
typescript
'use client';

import { ErrorBoundary } from 'react-error-boundary';

function ErrorFallback({ error, resetErrorBoundary }) {
  return (
    <div role="alert" className="p-4 border border-red-300 rounded">
      <h2>Algo salió mal</h2>
      <p>{error.message}</p>
      <Button onClick={resetErrorBoundary}>Intentar de nuevo</Button>
    </div>
  );
}

function App() {
  return (
    <ErrorBoundary FallbackComponent={ErrorFallback}>
      <YourComponent />
    </ErrorBoundary>
  );
}

Error Types

错误类型

  • 400 Bad Request: Invalid input
  • 401 Unauthorized: Not authenticated
  • 403 Forbidden: Not authorized
  • 404 Not Found: Resource doesn't exist
  • 500 Internal Server Error: Server error
  • 503 Service Unavailable: Service down
  • 400 Bad Request:无效输入
  • 401 Unauthorized:未认证
  • 403 Forbidden:无访问权限
  • 404 Not Found:资源不存在
  • 500 Internal Server Error:服务端错误
  • 503 Service Unavailable:服务不可用

Best Practices

最佳实践

  • Log errors with full context
  • Never expose stack traces to users
  • Provide actionable error messages
  • Implement retry logic for transient errors
  • Use error boundaries for React components
  • 记录带完整上下文的错误日志
  • 永远不要向用户暴露栈追踪信息
  • 提供可执行的错误提示指引
  • 为瞬时错误实现重试逻辑
  • 为React组件使用Error Boundary