1. Sentry によるエラー追跡
npx @sentry/wizard@latest -i nextjs
// sentry.client.config.ts
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
tracesSampleRate: 0.1, // 10% of transactions
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
integrations: [
Sentry.replayIntegration(),
Sentry.feedbackIntegration({ colorScheme: 'system' }),
],
});
// app/global-error.tsx
'use client';
import * as Sentry from '@sentry/nextjs';
import { useEffect } from 'react';
export default function GlobalError({ error, reset }: {
error: Error & { digest?: string };
reset: () => void;
}) {
useEffect(() => {
Sentry.captureException(error);
}, [error]);
return (
<html>
<body>
<h2>Đã xảy ra lỗi!</h2>
<button onClick={reset}>Thử lại</button>
</body>
</html>
);
}
2. ロギングのベストプラクティス
// lib/logger.ts
import pino from 'pino';
export const logger = pino({
level: process.env.LOG_LEVEL || 'info',
transport: process.env.NODE_ENV === 'development'
? { target: 'pino-pretty' }
: undefined,
formatters: {
level(label) { return { level: label }; },
},
base: {
env: process.env.NODE_ENV,
service: 'nextjs-app',
},
});
// Sử dụng
logger.info({ userId: '123', action: 'login' }, 'User logged in');
logger.error({ err: error, requestId }, 'Request failed');
3. セキュリティヘッダー
// next.config.ts
const securityHeaders = [
{
key: 'X-DNS-Prefetch-Control',
value: 'on',
},
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
{
key: 'X-Content-Type-Options',
value: 'nosniff',
},
{
key: 'X-Frame-Options',
value: 'DENY',
},
{
key: 'X-XSS-Protection',
value: '1; mode=block',
},
{
key: 'Referrer-Policy',
value: 'strict-origin-when-cross-origin',
},
{
key: 'Permissions-Policy',
value: 'camera=(), microphone=(), geolocation=()',
},
{
key: 'Content-Security-Policy',
value: "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';",
},
];
const config = {
async headers() {
return [{ source: '/:path*', headers: securityHeaders }];
},
};
4. ヘルスチェック
// app/api/health/route.ts
import { NextResponse } from 'next/server';
import { db } from '@/lib/db';
export async function GET() {
try {
// Check database
await db.$queryRaw`SELECT 1`;
return NextResponse.json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
checks: {
database: 'ok',
memory: process.memoryUsage(),
},
});
} catch (error) {
return NextResponse.json(
{ status: 'unhealthy', error: 'Database connection failed' },
{ status: 503 }
);
}
}
// app/api/ready/route.ts — Kubernetes readiness probe
export async function GET() {
// Check all external dependencies
const checks = await Promise.allSettled([
db.$queryRaw`SELECT 1`,
fetch(process.env.REDIS_URL + '/ping'),
]);
const allHealthy = checks.every(c => c.status === 'fulfilled');
return NextResponse.json(
{ ready: allHealthy },
{ status: allHealthy ? 200 : 503 }
);
}
5. レート制限
// middleware.ts — Simple rate limiting
import { NextRequest, NextResponse } from 'next/server';
const rateLimit = new Map<string, { count: number; resetTime: number }>();
export function middleware(request: NextRequest) {
if (!request.nextUrl.pathname.startsWith('/api')) {
return NextResponse.next();
}
const ip = request.headers.get('x-forwarded-for') || 'unknown';
const now = Date.now();
const windowMs = 60 * 1000; // 1 minute
const maxRequests = 100;
const record = rateLimit.get(ip);
if (!record || now > record.resetTime) {
rateLimit.set(ip, { count: 1, resetTime: now + windowMs });
return NextResponse.next();
}
if (record.count >= maxRequests) {
return NextResponse.json(
{ error: 'Too many requests' },
{ status: 429, headers: { 'Retry-After': '60' } }
);
}
record.count++;
return NextResponse.next();
}
6. 制作チェックリスト
| カテゴリ | アイテム | ステータス |
|---|---|---|
| セキュリティ | 設定されたセキュリティヘッダー | ☐ |
| セキュリティ | CSRF 保護 (サーバー アクション) | ☐ |
| セキュリティ | レート制限が有効になっています | ☐ |
| セキュリティ | 環境変数が検証されました | ☐ |
| パフォーマンス | 最適化された画像 (次/画像) | ☐ |
| パフォーマンス | フォントの最適化 (次へ/フォント) | ☐ |
| パフォーマンス | バンドルの分析と最適化 | ☐ |
| モニタリング | エラー追跡 (セントリー) | ☐ |
| モニタリング | 構造化されたロギング | ☐ |
| モニタリング | ヘルスチェックエンドポイント | ☐ |
| デプロイ | Docker のマルチステージ ビルド | ☐ |
| デプロイ | CI/CD パイプライン | ☐ |
| デプロイ | CI でのデータベースの移行 | ☐ |
| SEO | サイトマップとrobots.txt | ☐ |
| SEO | OpenGraph と構造化データ | ☐ |
🎉 おめでとうございます! React & Next.js コースの基本から上級までを完了しました。知識を実際のプロジェクトに応用してください。