React+Node项目Profile组件fetch返回HTML致JSON解析错误求助
Let's break down the root cause and fix this issue step by step.
The Problem: Relative Path Mismatch
The key issue here is how your fetch request is constructed in the read function of api-user.js. When your Profile component loads at a route like /user/:userId, using a relative path like api/users/${params.userId} causes the browser to make a request to /user/api/users/:userId instead of the intended /api/users/:userId.
Since your backend doesn't have a route for /user/api/users/:userId, it returns your React app's index.html file (the default fallback for unmatched routes), which is why you're getting the SyntaxError: Unexpected token < in JSON at position 0 error—you're trying to parse HTML as JSON.
Other components work because they're likely loaded at the root path (/), so the relative path api/users/ resolves correctly to /api/users/. Postman works because you're explicitly calling the correct absolute path.
The Fix: Use Absolute Paths for API Requests
Update all your API fetch calls to use absolute paths (add a leading slash to the URL):
Modified api-user.js
const create = (user) => { return fetch('/api/users/', { // Added leading slash method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify(user) }).then((res) => { return res.json() }).catch((err) => { console.log(err) }) } const list = () => { return fetch('/api/users/', { // Added leading slash method: 'GET' }).then((res) => { return res.json() }).catch((err) => { console.log(err) }) } const read = (params, credentials) => { return fetch(`/api/users/${params.userId}`, { // Added leading slash method: 'GET', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + credentials.t } }) .then((res) => { return res.json() }).catch((err) => { console.log(err) }) } const update = (params, credentials, user) => { return fetch(`/api/users/${params.userId}`, { // Added leading slash method: 'PUT', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + credentials.t }, body: JSON.stringify(user) }).then((res) => { return res.json() }).catch((err) => { console.log(err) }) } const remove = (params, credentials) => { return fetch(`/api/users/${params.userId}`, { // Added leading slash method: 'DELETE', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + credentials.t } }).then((res) => { return res.json() }).catch((err) => console.log(err)) } export {create, list, read, update, remove}
Additional Checks (Just to Be Sure)
- Verify Backend Route: Double-check that your backend has a GET route for
/api/users/:userId(you mentioned Postman works, so this is likely fine). - Inspect Network Tab: After making the change, open your browser's DevTools > Network tab, load the Profile page, and confirm the request URL points to
http://your-domain/api/users/:userId(no/user/prefix included). - Add Error Handling: You can enhance robustness by checking HTTP status codes before parsing JSON, to catch errors like 401 or 404:
.then((res) => { if (!res.ok) throw new Error(`Request failed: ${res.status}`); return res.json() })
This should resolve the issue where your Profile component receives HTML instead of user JSON data.
内容的提问来源于stack exchange,提问作者eaglesdgreat

