我有一个如下所示的路线处理程序
应用程序/api/交易/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
响应。const transactions: Transaction[] | TransactionError = await raw.json();
如果我这样做的话,这种类型对我来说似乎很混乱并且无法扩展。只是想知道 nextjs 中处理错误的最佳结构是什么?
如果错误的数据以 json 形式包含在响应正文中,则获取它的唯一方法是
raw.json()
,因此不会有神奇的方法来处理它。您的方法是正确的,但我可以向您展示一些使用数据的技巧。
您可以检查属性和
typeof
数据是否完全适合类型划分,如下所示:
if(Array.isArray(transactions)) {
transactions.map(() => {}) // works fine and type-friendly
} else {
transactions.errorMessage // works fine and type-friendly
}
或者如果你想在很多地方这样做,甚至更干净:
function isTransactionError(data: unknown) data is TransactionError {
return data && data.errorMessage
}
if(isTransactionError(transactions)) {
transactions.errorMessage // works fine
} else {
transactions.map(() => {}) // works fine
}
您可以在这里阅读有关类型保护的更多信息:https://www.typescriptlang.org/docs/handbook/2/narrowing.html
您可以在单独的属性中返回数据和错误对象。大多数框架和 API 工具(例如 graphql)都做同样的事情。
// success:
{
data: [{...}, {...}], // here is your transactions
error: null
}
// failure:
{
data: null,
error: {...}
}
然后你也可以对其进行类型保护:
result.data?.map(() => {})
result.error?.errorMessage
raw.ok
)Mozilla 说这里:
Response 接口的
只读属性包含一个布尔值,指示响应是否成功(状态范围为 200-299)。ok
您可以这样使用它:
if(raw.ok) {
console.log("Success!")
} else {
console.log("Error :(")
}
但是,它对类型不友好。那么让我们来实现吧:
type ResponsePayload<TResult, TError = unknown> = {
data: TResult | null;
error: TError | null;
}
type ResponseWithPayload<TResult, TError = unknown> = Response & {
payload: ResponsePayload<TResult, TError>
}
async function withTypes<TResult, TError = unknown>(response: Promise<Response> | Response) {
const resp = await response as ResponseWithPayload<TResult, TError>;
const payload = await resp.json();
if(resp.ok) {
resp.payload = {
data: payload,
error: null,
}
} else {
resp.payload = {
data: null,
error: payload,
}
}
return resp;
}
并像这样使用它:
// example 1
const resp = await withTypes<Transaction[], TransactionError>(fetch("..."))
resp.payload.data?.map(() => {});
resp.payload.error?.errorMessage;
// example 2
const resp2 = await fetch("...");
const { payload } = await withTypes<Transaction[]>(resp2)
payload.data?.map(() => {});