From cf88d3a1d2eeb8d44f0d19b6b73ac84599aec5ea Mon Sep 17 00:00:00 2001 From: kurihada Date: Thu, 26 Feb 2026 20:20:59 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=A4=96=E9=83=A8=20API=20=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E5=A4=84=E7=90=86=20+=20=E5=AF=BC=E8=88=AA=20URL=20?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=20+=20reset/narrow=20=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E5=8F=8D=E9=A6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - #22: 高德 API fetch 加 try/catch,失败返回 503 而非泛化 500 - #23: buildNavUrl 校验 location.split(",") 结果长度和非空 - #24: handleReset/handleNarrow 检查 res.ok,失败时 toast 提示 --- src/app/api/location/regeo/route.ts | 9 ++++-- src/app/api/location/suggest/route.ts | 11 +++++-- src/app/api/room/create/route.ts | 9 ++++-- src/app/room/[id]/page.tsx | 46 +++++++++++++++++++-------- src/lib/navigation.ts | 6 ++-- 5 files changed, 58 insertions(+), 23 deletions(-) diff --git a/src/app/api/location/regeo/route.ts b/src/app/api/location/regeo/route.ts index 833cf8c..debc5b5 100644 --- a/src/app/api/location/regeo/route.ts +++ b/src/app/api/location/regeo/route.ts @@ -15,8 +15,13 @@ export const GET = apiHandler(async (req) => { url.searchParams.set("location", `${lng},${lat}`); url.searchParams.set("extensions", "base"); - const res = await fetch(url.toString()); - const data = await res.json(); + let data; + try { + const res = await fetch(url.toString()); + data = await res.json(); + } catch { + throw new ApiError("位置服务暂时不可用,请稍后重试", 503); + } if (data.status !== "1" || !data.regeocode) { return NextResponse.json({ name: null }); diff --git a/src/app/api/location/suggest/route.ts b/src/app/api/location/suggest/route.ts index 69fd5f1..b6abef4 100644 --- a/src/app/api/location/suggest/route.ts +++ b/src/app/api/location/suggest/route.ts @@ -1,5 +1,5 @@ import { NextResponse } from "next/server"; -import { apiHandler } from "@/lib/api"; +import { apiHandler, ApiError } from "@/lib/api"; import { requireAmapApiKey } from "@/lib/amap"; export const GET = apiHandler(async (req) => { @@ -13,8 +13,13 @@ export const GET = apiHandler(async (req) => { url.searchParams.set("keywords", keywords); url.searchParams.set("datatype", "poi"); - const res = await fetch(url.toString()); - const data = await res.json(); + let data; + try { + const res = await fetch(url.toString()); + data = await res.json(); + } catch { + throw new ApiError("位置服务暂时不可用,请稍后重试", 503); + } if (data.status !== "1" || !data.tips) return NextResponse.json([]); diff --git a/src/app/api/room/create/route.ts b/src/app/api/room/create/route.ts index 0ba1ba1..dd4e8b5 100644 --- a/src/app/api/room/create/route.ts +++ b/src/app/api/room/create/route.ts @@ -141,8 +141,13 @@ export const POST = apiHandler(async (req) => { url.searchParams.set("keywords", cuisine); } - const amapRes = await fetch(url.toString()); - const amapData = await amapRes.json(); + let amapData; + try { + const amapRes = await fetch(url.toString()); + amapData = await amapRes.json(); + } catch { + throw new ApiError("位置服务暂时不可用,请稍后重试", 503); + } let restaurants: Restaurant[] = []; if (amapData.status === "1" && amapData.pois?.length > 0) { diff --git a/src/app/room/[id]/page.tsx b/src/app/room/[id]/page.tsx index 0bdc340..e7c25c2 100644 --- a/src/app/room/[id]/page.tsx +++ b/src/app/room/[id]/page.tsx @@ -11,6 +11,7 @@ import { useRoomPolling } from "@/hooks/useRoomPolling"; import { getUserId } from "@/lib/userId"; import { joinRoom } from "@/lib/room"; import { getSceneConfig } from "@/lib/sceneConfig"; +import { useToast } from "@/hooks/useToast"; export default function RoomPage() { const params = useParams<{ id: string }>(); @@ -22,6 +23,7 @@ export default function RoomPage() { const [joinFailed, setJoinFailed] = useState(false); const [showLeaveConfirm, setShowLeaveConfirm] = useState(false); const leavingRef = useRef(false); + const toast = useToast(); const { userCount, match, matchType, matchLikes, runnerUps, likeCounts, swipeCounts, @@ -74,22 +76,38 @@ export default function RoomPage() { }, []); const handleReset = useCallback(async () => { - await fetch(`/api/room/${roomId}/reset`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ userId }), - }); - await mutate(); - }, [roomId, userId, mutate]); + try { + const res = await fetch(`/api/room/${roomId}/reset`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ userId }), + }); + if (!res.ok) { + const data = await res.json().catch(() => ({})); + throw new Error(data.error || "重置失败"); + } + await mutate(); + } catch (e) { + toast.show(e instanceof Error ? e.message : "重置失败"); + } + }, [roomId, userId, mutate, toast]); const handleNarrow = useCallback(async (restaurantIds: string[]) => { - await fetch(`/api/room/${roomId}/reset`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ userId, restaurantIds }), - }); - await mutate(); - }, [roomId, userId, mutate]); + try { + const res = await fetch(`/api/room/${roomId}/reset`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ userId, restaurantIds }), + }); + if (!res.ok) { + const data = await res.json().catch(() => ({})); + throw new Error(data.error || "缩小范围失败"); + } + await mutate(); + } catch (e) { + toast.show(e instanceof Error ? e.message : "操作失败"); + } + }, [roomId, userId, mutate, toast]); if (notFound || joinFailed) { return ( diff --git a/src/lib/navigation.ts b/src/lib/navigation.ts index 49f6871..86dc61b 100644 --- a/src/lib/navigation.ts +++ b/src/lib/navigation.ts @@ -2,8 +2,10 @@ import type { Restaurant } from "@/types"; export function buildNavUrl(restaurant: Restaurant): string { if (restaurant.location) { - const [lng, lat] = restaurant.location.split(","); - return `https://uri.amap.com/marker?position=${lng},${lat}&name=${encodeURIComponent(restaurant.name)}&callnative=1`; + const parts = restaurant.location.split(","); + if (parts.length === 2 && parts[0] && parts[1]) { + return `https://uri.amap.com/marker?position=${parts[0]},${parts[1]}&name=${encodeURIComponent(restaurant.name)}&callnative=1`; + } } return `https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(restaurant.name)}`; }