laravel中图片404的根源是未正确配置storage符号链接或误用路径;必须执行php artisan storage:link建立public/storage→storage/app/public软链,并通过storage::disk('public')->url()生成url,数据库存该url而非物理路径。

在 Laravel 中保存用户上传的图片后,前端页面始终显示 404,不是因为文件没存进去,而是数据库里存了 storage/app/public/xxx 这样的物理路径,或前端直接拼接 /public/uploads/xxx 这种错误 URL;真正可访问的链接必须由框架生成,且严格依赖磁盘配置与符号链接状态。
理解 storage/app 与 public/storage 的真实关系
所有上传文件默认写入 storage/app/ 目录,但该目录不对外 Web 可访问;Laravel 用 public/storage 这个符号链接作为“窗口”,它必须指向 storage/app/public,浏览器才能通过 /storage/xxx 访问到真实文件。
执行 php artisan storage:link 后,public/storage → storage/app/public 是操作系统级软链,不可替代为复制、移动或手动创建同名文件夹。
【public/storage 符号链接未建立,任何 /storage/ 开头的 URL 都必然 404】
若你在本地开发环境反复确认 public/storage 存在却仍 404,请检查 Web 服务器是否启用 FollowSymLinks(Apache)或 disable_symlinks off(Nginx)。
正确生成可访问 URL 的唯一可靠方式
方法一:使用 Storage::url()(仅限 public 磁盘)
1. 确保文件已存入 public 磁盘:Storage::disk('public')->put('images/avatar.jpg', $file) → 文件落至 storage/app/public/images/avatar.jpg
2. 调用 url() 获取路径:Storage::disk('public')->url('images/avatar.jpg') → 返回 /storage/images/avatar.jpg
3. 在 Blade 中渲染:<img src="%7B%7B%20Storage::disk('public')->url('images/avatar.jpg')%20%7D%7D">
注意:不能对 local 磁盘调用 url(),会抛出 “UrlGenerator not supported” 异常——这是驱动限制,不是代码写错。
方法二:配合 asset() 使用(需路径前缀为 storage/)
先确保已运行 php artisan storage:link,再统一用 asset() 包裹 Storage::url() 结果:{{ asset(Storage::disk('public')->url('images/avatar.jpg')) }}
这等价于直接写 {{ Storage::disk('public')->url('images/avatar.jpg') }},因为 Storage::url() 已返回以 /storage/ 开头的相对路径,asset() 不做二次拼接。
【绝对不要写 asset('storage/app/public/images/avatar.jpg') —— 该路径在 public/ 下根本不存在】
彻底避开硬编码路径的三步实操
第一步:控制器中上传并获取 URL
$path = 'uploads/articles/' . uniqid() . '.' . $request->file('cover')->getClientOriginalExtension();
Storage::disk('public')->put($path, $request->file('cover'));
$url = Storage::disk('public')->url($path); // ✅ 动态生成,适配本地/S3
第二步:存入数据库的必须是 $url,不是 $path 或物理路径
Article::create([ 'title' => $request->title, 'cover_url' => $url // 不是 $path,更不是 public_path('uploads/...') ])
第三步:视图中直接输出
<img src="%7B%7B%20%24article->cover_url%20%7D%7D">











