React前端对接Rails 6+ Active Storage API实现图片上传失败如何解决?
解决方案
核心问题说明
你两处写法的核心问题都是没有使用FormData格式提交请求:直接将文件对象放入普通JSON对象中,浏览器无法正确序列化二进制文件内容,Rails后端也无法解析到符合Active Storage要求的上传文件参数。另外React Hook Form对文件输入框默认返回FileList对象,需要单独取第一个元素拿到文件实例。
原生useState版本修复
修改提交逻辑,用FormData包装所有参数:
const [image, setImage] = useState(null) const handleSubmit = () => { const formData = new FormData() // 按照Rails强参数的嵌套规则拼接参数key formData.append('product[user_id]', props.user_id) formData.append('product[name]', name) formData.append('product[category]', category) formData.append('product[image]', image) // 注意:如果你的ApiService是axios等封装的,不要手动设置Content-Type为multipart/form-data,传FormData时浏览器会自动生成带分隔符的请求头,手动设置反而会丢失boundary导致解析失败 ApiService.create(`products`, formData) } // in the return <input type="file" name="image" onChange={e => setImage(e.target.files[0])} />
React Hook Form版本修复
React Hook Form绑定文件输入后,返回的是FileList对象,取第一个元素即可拿到文件,同样用FormData提交:
const { register, handleSubmit } = useForm(); const onSubmit = (data) => { // 取FileList的第一个元素得到文件实例 const imageFile = data.image?.[0] if (!imageFile) return // 可加文件非空校验 const formData = new FormData() formData.append('product[name]', data.name) formData.append('product[user_id]', props.user_id) formData.append('product[category]', category) formData.append('product[image]', imageFile) ApiService.create(`products`, formData) } ; return ( <form onSubmit={handleSubmit(onSubmit)}> <TextField id="name" label="Name" type="text" required fullWidth {...register('name')} /> <input type="file" {...register('image')} /> <Button type="submit" fullWidth variant="contained" color="primary" > Submit </Button> </form> )
额外注意事项
- 确认你的ApiService全局配置没有强制设置
Content-Type: application/json,如果有该配置需要对上传接口单独覆盖 - 若存在跨域问题,确认Rails的
rack-cors配置放开了multipart相关的请求头权限
内容的提问来源于stack exchange,提问作者Rémy Le Dernier Bop
相关产品推荐
相关产品推荐

