You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JSON输入意外结束报错排查:旧数据详情页无法加载问题

问题

我遇到了Uncaught (in promise) Syntax Error: Unexpected end of JSON input报错,目前通过GET请求获取数据并在详情页展示。新创建的条目能正常显示,但JSON文件中预先编写的旧数据,虽能被服务端加载、getAll接口也能获取,进入详情页却触发报错无法展示;应用启动后新增的条目则完全正常。


相关代码

recipeService 中的 getOne 方法

export const getOne = async (recipeId) => {
    return await fetch(`${baseUrl}/recipes/${recipeId}`)
    .then(res => res.json())
}

recipeService 中的 getAll 方法

export const getAll = async () => {
    let response = await fetch(`${baseUrl}/recipes`)

    let recipes = await response.json();

    let result = Object.values(recipes);

    return result;
}

Details 组件代码

import "./Details.css";
import { Link, NavLink, useParams,useNavigate } from 'react-router-dom';
import { BrowserRouter,Route,Routes, Switch, Redirect } from 'react-router-dom';
import React, { useEffect, useLayoutEffect, useState } from 'react';
import * as recipeService from "../../../services/recipeService";


const Details = () =>  {

    const [recipe,setRecipe] = useState({}); 
    const {recipeId} = useParams();
    
    const recipesd = async () => {
        let reciperes =   await recipeService.getOne(recipeId);

        setRecipe(reciperes);
    };


    useEffect(() => { recipesd(recipe); },[]);



    const history = useNavigate();
    
    useLayoutEffect(() => {
        window.scrollTo(0, 0)
    });
    
    const scrollToTop = () => {
        window.scrollTo(0, 0)
    }

    return (
        <div>
    <section className="sec11">
        <h1>{recipe.name}</h1>
        <button smooth="true" className="leave" onClick={()=> history(-1)}><i class="fas fa-solid fa-xmark"></i></button>
        <article className="main">
            <article className="artsm">
                <h4>Ingredients</h4>
                <p className="ingre">
                    {recipe.ingredients}
                </p>
            </article>
            <article className="artm">
                <img src={recipe.imageUrl}/>
                <hr/>
                <h4>{recipe.name}</h4>
                <p>Cooking Time: {recipe.time}min</p>
                <p className="cut-text">{recipe.instructions}</p>
            </article>
            <article className="artsm">
                <h4>Instructions</h4>
                <p className="inst">
                    {recipe.instructions}
                </p>
            </article>
        </article>
        <article className="comment">
            <form className="form">
                <textarea name="comment" placeholder=" Comment..."></textarea>
                <input className="btncom" type="submit" value="Comment"/>
            </form>
        </article>
        <button className="gob" onClick={()=> history(-1)}><i class="fas fa-solid fa-arrow-left-long"></i></button>
    </section>
        <section className="sec5navl">
        <ul>
            <li><Link smooth= "true" to="/"><i className="fas fa-solid fa-book-bookmark"></i></Link>Home</li>
            <li><Link smooth= "true" to="/recipes"><i className="fas fa-thin fa-bowl-rice"></i></Link>Recipes</li>
            <li><Link smooth= "true" to="/personal-list"><i className="fas fa-solid fa-list-ul"></i></Link>Your Recipes</li>
            <li><Link smooth= "true" to="/favourites"><i className="fa-solid fa-heart"></i></Link>Favourites</li>
            <li><Link smooth= "true" to="/create-recipe"><i className="fas fa-solid fa-plus"></i></Link>Add Recipe</li>
            <li><Link smooth= "true" to="/user-profile"><i className="fas fa-solid fa-user"></i></Link>Your Profile</li>
            <li><Link smooth= "true" onClick={scrollToTop} to={`/recipe-details/${recipe._id}`}><i class="fas fa-solid fa-arrow-up"></i></Link>Up</li>
        </ul>
        </section>
        </div>
    );
}

export default Details;

预先定义的JSON数据片段

[
    {
        "_id": "62d6be17360d7443f08639d7",
        "name": "Caponata pasta",
        "time": "20",
        "imageUrl": "https://images.immediate.co.uk/production/volatile/sites/30/2020/08/caponata-pasta-a0027c4.jpg?resize=960,872?quality=90&webp=true&resize=375,341",
        "ingredients": "4 tbsp olive oil 1 large onion, finely chopped 4 garlic cloves, finely sliced 250g chargrilled Mediterranean veg (peppers and aubergines, if possible) from a jar, pot or deli counter, drained if in oil (you can use this oil in place of the olive oil and roughly chopped 400g can chopped tomatoes 1 tbsp small capers 2 tbsp raisins 350g rigatoni, penne or another short pasta shape bunch basil leaves, picked parmesan (or vegetarian alternative), shaved, to serve",
        "instructions": "STEP 1 Heat the oil in a large pan and cook the onion for 8-10 mins until starting to caramelise (or for longer if you have time – the sweeter the better). Add the garlic for the final 2 mins of cooking time. STEP 2 Tip in the mixed veg, tomatoes, capers and raisins. Season well and simmer, uncovered, for 10 mins, or until you have a rich sauce. STEP 3 Meanwhile, boil the kettle. Pour the kettleful of water into a large pan with a little salt and bring back to the boil. Add the pasta and cook until tender with a little bite, then drain, reserving some of the pasta water. Tip the pasta into the sauce, adding a splash of pasta water if it needs loosening. Scatter with the basil leaves and parmesan, if you like, and serve straight from the pan",
        "createdAt": "2022-07-19T14:22:15.446Z",
        "updatedAt": "2022-07-19T14:22:15.446Z"
    }
]

解决方案

1. 先排查服务端返回内容

Unexpected end of JSON input本质是请求返回的不是有效JSON(甚至是空内容)。先修改getOne方法,打印请求状态和原始返回内容:

export const getOne = async (recipeId) => {
    const res = await fetch(`${baseUrl}/recipes/${recipeId}`);
    console.log('请求状态码:', res.status);
    console.log('原始返回内容:', await res.text()); // 先看文本内容,不要直接转JSON
    return res.json();
}

如果状态码是404,说明服务端找不到旧数据对应的ID;如果是200但内容为空/非JSON,直接定位服务端接口问题。

2. 检查旧数据的ID匹配度

确认详情页路由中的recipeId和旧数据的_id完全一致(比如62d6be17360d7443f08639d7),避免传错ID导致服务端返回空内容。

3. 排查服务端接口逻辑差异

getAll能拿到旧数据但getOne不行,大概率是服务端接口逻辑问题:

  • 旧数据存储为数组格式,而新数据存储为对象键值对(getAll中用了Object.values(recipes),说明返回的是对象转数组)
  • 服务端getOne接口可能只处理对象格式的数据,没做数组遍历查找的逻辑,导致旧数据无法通过ID匹配返回。

4. 前端添加错误处理

不管服务端问题,先给前端加错误捕获,避免报错中断页面:

export const getOne = async (recipeId) => {
    try {
        const res = await fetch(`${baseUrl}/recipes/${recipeId}`);
        if (!res.ok) throw new Error(`请求失败: ${res.status}`);
        return await res.json();
    } catch (err) {
        console.error('获取单条数据失败:', err);
        return {}; // 返回空对象避免页面报错
    }
}

同时在Details组件中判断返回值:

const recipesd = async () => {
    let reciperes = await recipeService.getOne(recipeId);
    if (reciperes._id) { // 确认数据有效再更新状态
        setRecipe(reciperes);
    } else {
        console.log('未找到对应食谱数据');
        // 可添加跳转404页面或用户提示逻辑
    }
};

5. 验证路由参数传递

确认列表页跳转到详情页时,传递的参数是旧数据的_id,比如链接格式为/recipe-details/${item._id},避免传错字段导致请求错误。


内容的提问来源于stack exchange,提问作者DimitriTfb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 19:48:45