Next.js路由处理器错误处理的TypeScript类型问题及最佳方案咨询
Next.js 接口错误处理的最佳结构咨询
我编写了如下Next.js路由处理器:app/api/transactions/route.ts
import { NextRequest, NextResponse } from "next/server"; import { AxiosError } from "axios"; import axios from "../axios"; import { AxiosResponse } from "axios"; import { Transaction } from "../../../types"; interface Error { message: string[]; statusCode: number; } export async function GET(request: NextRequest) { try { const transactionsRes: AxiosResponse<Transaction[]> = await axios.get( `/transactions` ); return NextResponse.json(transactionsRes.data); } catch (error) { const axiosError = error as AxiosError<Error>; return NextResponse.json( { error: axiosError?.response?.data.message }, { status: axiosError?.response?.data.statusCode } ); } }
同时在MyComponent.tsx中调用该接口:
export const MyComponent = async() => { const raw = await fetch('api/transaction'); const transactions: Transaction[] = await raw.json(); if (transactions.error) { throw new Error(transactions.error); } ... }
我还使用error.tsx作为错误边界捕获错误。
目前的问题是:按此方式处理错误时,需将接口响应类型定义为Transaction[] | TransactionError,该类型既混乱又不易扩展,想咨询Next.js中错误处理的最佳结构是什么?
最佳错误处理结构方案
1. 统一API响应格式
前后端约定统一的响应外层结构,无论成功失败都遵循该格式,彻底消除联合类型的困扰。
首先定义通用响应类型:
// types/api.ts export interface ApiResponse<T = unknown> { success: boolean; data?: T; error?: { message: string | string[]; code?: number; }; }
修改路由处理器,统一返回该结构:
// app/api/transactions/route.ts import { NextRequest, NextResponse } from "next/server"; import { AxiosError } from "axios"; import axios from "../axios"; import { Transaction } from "../../../types"; import { ApiResponse } from "../../../types/api"; interface BackendError { message: string[]; statusCode: number; } export async function GET(request: NextRequest) { try { const transactionsRes = await axios.get<Transaction[]>(`/transactions`); return NextResponse.json<ApiResponse<Transaction[]>>({ success: true, data: transactionsRes.data }); } catch (error) { const axiosError = error as AxiosError<BackendError>; const errorData = axiosError?.response?.data; return NextResponse.json<ApiResponse>({ success: false, error: { message: errorData?.message || "获取交易数据失败", code: errorData?.statusCode || 500 } }, { status: errorData?.statusCode || 500 }); } }
2. 前端封装统一请求工具
把请求逻辑封装到工具函数中,自动处理响应格式和错误抛出,组件无需关注类型判断:
// utils/fetchApi.ts import { ApiResponse } from "@/types/api"; export async function fetchApi<T>(url: string): Promise<T> { const res = await fetch(url); const response: ApiResponse<T> = await res.json(); if (!response.success) { const errorMessage = Array.isArray(response.error?.message) ? response.error.message.join(", ") : response.error?.message || "请求失败"; throw new Error(errorMessage); } return response.data as T; }
组件中直接使用:
// MyComponent.tsx import { fetchApi } from "@/utils/fetchApi"; import { Transaction } from "../../types"; export const MyComponent = async() => { // 直接拿到Transaction[]类型,错误会被error.tsx自动捕获 const transactions = await fetchApi<Transaction[]>('api/transactions'); ... }
3. 基于HTTP状态码的前置判断
如果不想修改后端响应格式,可以利用HTTP状态码提前识别错误:
// utils/fetchApi.ts 优化版 export async function fetchApi<T>(url: string): Promise<T> { const res = await fetch(url); // 非2xx状态码直接抛出错误 if (!res.ok) { const errorRes = await res.json().catch(() => null); const message = errorRes?.error?.message || `${res.status} 请求失败`; throw new Error(message); } // 这里返回的就是纯成功数据类型 const data = await res.json(); return data as T; }
4. 强化错误边界的处理能力
- 保持
error.tsx作为页面级错误边界,捕获组件树中的异步错误。 - 可以封装自定义错误类,携带状态码、错误类型等信息,让
error.tsx能展示更精准的提示:
// types/errors.ts export class ApiError extends Error { statusCode: number; constructor(message: string, statusCode: number) { super(message); this.statusCode = statusCode; this.name = "ApiError"; } }
在请求工具中抛出这个自定义错误,error.tsx就能根据错误类型展示不同内容。
总结
优先推荐统一API响应格式的方案,它能让前后端错误处理逻辑更一致,彻底消除联合类型的混乱。如果无法修改后端,则选择基于HTTP状态码的前置判断方案,同样能简化前端类型处理。两种方案都能让代码更易维护和扩展。
内容的提问来源于stack exchange,提问作者CCCC
相关产品推荐
相关产品推荐

