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

Laravel后端文件上传报错:Call to a member function move() on string

Laravel后端文件上传失败问题排查与解决

Laravel后端无法将文件上传/移动到指定的uploads目录,取消注释return $request->image时能返回图片名称,但调用$request->image->move()方法失效,怀疑是前端传递的文件请求为字符串类型导致。前端使用React + react-router-dom的Form组件与useLoaderData,配合自定义axiosClient发送请求。


前端代码

ProductAdd组件

export default function ProductAdd(){
    const [image,setImage] = useState(null)

    const imageHandler = (e) =>{
       setImage(e.target.files[0])
    }

    return(
        <Form id="clear-form" method="post" replace>
            <div className="mb-4 relative">
                <label>File Picture</label>
                <input name="image" onChange={imageHandler} type="file" />
            </div>
            <div>
                <button type="submit">Create</button>
            </div>
        </Form>
    )
}

ProductAddActionLoader

export const ProductAddActionLoader = async({ request }) =>{
    const formData = await request.formData();
    const payload = {
        image:formData.get('image'),
    }

    return await axiosClient.post('admin/fruit/create',payload)
        .then(({data})=>{
            console.log(data)
            return data
        }).catch(error=>{
            console.log(error)
            return error
        })
}

路由配置(router.jsx)

{
    path:'create',
    element:<ProductAdd/>,
    action:ProductAddActionLoader
}

后端代码(ProductController)

public function create(Request $request){
    // return $request->image;
    $fileName = time().'.'.$request->image;
    $request->image->move(public_path('uploads'), $fileName);
    return response('Data has been Added',200);
}

问题原因

核心问题是前端通过axios发送请求时,直接将File对象放到普通JSON payload里传递,导致后端接收的是文件名称字符串而非UploadedFile实例。axios默认会将普通对象序列化为JSON,无法正确传输文件二进制数据。


解决方案

1. 前端修改:使用FormData传递文件

在ActionLoader中,直接将formData作为请求体发送,不要手动封装成普通对象:

export const ProductAddActionLoader = async({ request }) =>{
    const formData = await request.formData();
    // 直接发送formData,而非封装成payload对象
    return await axiosClient.post('admin/fruit/create', formData, {
        headers: {
            'Content-Type': 'multipart/form-data'
        }
    })
    .then(({data})=>{
        console.log(data)
        return data
    }).catch(error=>{
        console.log(error)
        return error
    })
}

注:axios在传递FormData时会自动设置Content-Type为multipart/form-data,显式声明可避免兼容性问题。

2. 后端修改:验证文件并正确获取扩展名

后端需要确保接收的是UploadedFile实例,同时修正文件扩展名的获取方式:

public function create(Request $request){
    // 验证文件是否存在且有效
    $request->validate([
        'image' => 'required|file|mimes:jpg,jpeg,png,gif'
    ]);

    $file = $request->file('image');
    // 获取文件原始扩展名
    $extension = $file->getClientOriginalExtension();
    $fileName = time() . '.' . $extension;
    // 移动文件到uploads目录
    $file->move(public_path('uploads'), $fileName);
    
    return response('Data has been Added',200);
}

3. 额外检查项

  • 确保public/uploads目录存在且有写入权限:
    mkdir -p public/uploads
    chmod -R 755 public/uploads
    
  • react-router-dom的Form组件在包含file输入时,会自动设置enctype="multipart/form-data",无需手动配置。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 03:13:16