React fetch拉取接口解析JSON报Unexpected token <错误排查
报错根因
SyntaxError: Unexpected token < in JSON at position 0 这个错误本质是你试图解析的内容根本不是合法JSON,而是HTML文档:HTML内容的第一个字符通常是<(比如<!DOCTYPE html>的开头),和JSON要求的起始字符({/[/"/数字等)不匹配,所以解析失败。
你代码里的核心问题有3个:
- 定义的接口地址缺少协议头:你写的
url是www.thecocktaildb.com/api/json/v1/1/search.php?s=,没有加https://前缀。fetch遇到不带协议的地址时,会把它当成当前站点的相对路径拼接——比如你本地开发时跑在localhost:3000,实际请求地址会变成http://localhost:3000/www.thecocktaildb.com/api/json/v1/1/search.php?s=a,这个地址不存在,返回的是React单页应用的index.html入口文件,自然是HTML格式。你直接在浏览器地址栏访问能拿到数据,是因为浏览器会自动给地址补全https://协议,fetch不会做这个自动补全。 - 缺少响应状态校验:fetch本身只有网络完全不通的时候才会抛出异常,哪怕接口返回404、500、403这类HTTP错误状态,fetch都会正常返回response对象,如果你不校验状态直接解析,很可能拿到的是服务器返回的错误页HTML,同样触发这个解析错误。
- 逻辑遗漏:你拿到解析后的
data之后,没有把数据存入cocktails状态,就算请求成功页面也拿不到返回的鸡尾酒数据。
修复步骤
- 给接口地址补全HTTPS协议前缀
- 解析JSON前先校验响应是否为正常2xx状态
- 把接口返回的酒品数据存入对应状态,异常分支也要重置loading状态避免页面一直加载
修复后可运行代码
import React,{useContext,useState,useEffect} from 'react' // 补全https协议头 const url = 'https://www.thecocktaildb.com/api/json/v1/1/search.php?s=' export default function AppProvider({children}) { const [loading,setLoading] = useState(true) const [searchTerm,setSearchTerm] = useState('a') const [cocktails,setCocktails] = useState([]) const fetchUrl = async ()=>{ setLoading(true) try { const response = await fetch(`${url}${searchTerm}`) // 校验响应状态,非2xx状态直接抛错进入catch分支 if (!response.ok) { throw new Error(`请求失败,状态码:${response.status}`) } const data = await response.json() // 接口无匹配结果时drinks为null,这里兜底为空数组避免渲染报错 setCocktails(data.drinks || []) setLoading(false) } catch (error) { console.log(error) setLoading(false) } } useEffect(()=>{ fetchUrl() },[searchTerm]) // 原有context传递相关逻辑保持不变即可 }
可选优化
如果后续搜索词输入比较频繁,可以加防抖减少无效请求,同时可以用AbortController处理请求竞态问题,避免先发的慢请求覆盖新请求的返回结果。
内容的提问来源于stack exchange,提问作者Naimur Sharon
相关产品推荐
相关产品推荐

