用户注册后个人资料更新失败问题求助:Postman可正常执行,前端疑似引发JSON解析错误
解决前端更新用户资料时的JSON解析错误与请求pending问题
首先咱们来定位问题根源:你的后端用了formidable来处理multipart/form-data格式的请求(因为要支持图片上传),但前端的请求配置和数据格式完全不匹配,导致了两个核心问题:
- 直接传
user对象时,请求头设了Content-Type: application/json,但实际发送的是FormData格式内容,后端的body-parser试图把它解析成JSON,自然抛出语法错误 - 用
JSON.stringify(user)时,因为user里包含File类型的图片数据,JSON无法序列化二进制内容,导致请求卡住pending
第一步:修正前端Action代码
更新你的update action,移除手动设置的Content-Type头(FormData会自动生成带边界标识的正确multipart/form-data请求头),直接传递FormData作为请求体:
export const update = (userId, token, userFormData) => { return fetch(`${API}/user/${userId}`, { method: "PUT", headers: { Accept: 'application/json', // 移除Content-Type,让浏览器自动处理 Authorization: `Bearer ${token}` }, body: userFormData // 直接传递FormData实例 }) .then(res => { return res.json(); }) .catch(err => { console.log(err); }); };
第二步:修正前端组件的表单数据处理逻辑
当前的handleChange每次修改字段都会新建FormData,导致之前的字段丢失,应该维护一个全局的FormData实例,每次修改时更新对应字段:
const UserProfileUpdate = ({match}) => { const [values, setValues] = useState({ firstname: '', lastname: '', email: '', photo: '', about: '', error: false, success: false, userData: new FormData() // 初始化空的FormData实例 }); const {about,userData, photo, firstname, lastname, email, error, success} = values; const {user: { _id }} = isAuthenticated(); const token = isAuthenticated().token; const init = userId => { read(userId, token).then(data => { if(data.error){ setValues({...values, error: true}) } else { // 用现有用户数据初始化FormData const initialFormData = new FormData(); initialFormData.set('firstname', data.firstname); initialFormData.set('lastname', data.lastname); initialFormData.set('email', data.email); initialFormData.set('about', data.about); setValues({ ...values, firstname: data.firstname, lastname: data.lastname, email: data.email, photo: data.photo, about: data.about, userData: initialFormData }) } }) }; useEffect(() => { init(match.params.userId); }, []); const handleChange = name => e => { const value = name === 'photo' ? e.target.files[0] : e.target.value; // 基于现有FormData更新字段,避免丢失之前的内容 const updatedFormData = new FormData(userData); updatedFormData.set(name, value); setValues({ ...values, [name]: value, userData: updatedFormData, error: false, success: false }); }; // handleSubmit逻辑保持不变,直接传递维护好的userData即可 const handleSubmit = e => { e.preventDefault(); update(match.params.userId, token, userData).then(data => { if (data.error) { console.log(data.error); } else { updateUser(data, () => { setValues({ ...values, firstname: data.firstname, lastname: data.lastname, email: data.email, about: data.about, success: true }); }); } }); }; const redirectUser = (success) => { if(success){ return <Redirect to={`/dashboard/${_id}/`}/> } } // 组件其余渲染逻辑... };
为什么这样能解决问题?
- 请求格式匹配:后端的
formidable专门处理multipart/form-data请求,前端传递FormData时,浏览器会自动设置正确的请求头(包含boundary参数),后端能正确解析字段和文件 - 避免JSON序列化错误:FormData原生支持文件上传,不需要手动序列化,解决了JSON无法处理二进制数据的问题
- 完整的表单数据:每次修改时基于现有FormData更新字段,不会丢失之前填写的内容
这样修改后,前端的请求就能和Postman一样正常工作,后端也能正确解析并处理用户资料的更新了。
内容的提问来源于stack exchange,提问作者Emmanuel Oga
相关产品推荐
相关产品推荐

