迁移后 storage 图片 404 的根本原因是软链接失效、缓存残留及权限错位三者叠加;须按顺序手动删除 public/storage、执行 php artisan optimize:clear 清缓存、重新 storage:link、验证链接与权限,并确保上传使用 Storage::disk('public')->store()。

迁移后 storage 路径报错,基本就是软链接失效 + 缓存残留 + 权限错位三者叠加。单独执行 php artisan storage:link 通常无效,必须按顺序清理、重建、验证。
public/storage 软链接指向错误或已损坏
迁移后 public/storage 很可能还指向旧项目的 storage/app/public(路径已不存在),或链接文件本身被当成普通目录保留下来。浏览器访问 /storage/xxx.jpg 返回 404,但文件明明在 storage/app/public/ 里,就是这个原因。
- 手动删掉旧链接:
rm -f public/storage(只删链接,别碰storage/app/public/里的文件) - 检查是否真删干净:
ls -la public/ | grep storage,输出应为空 - 不要依赖 “link already exists” 提示——它只检测链接文件是否存在,不校验目标路径有效性
Artisan 缓存仍引用旧链接状态
asset('storage/xxx.jpg') 生成的 URL 是缓存过的,哪怕你重建了软链接,视图和配置缓存里还是旧路径。不清理就等于没修。
- 运行完整清缓存命令:
php artisan optimize:clear - 等效于依次执行:
config:clear、cache:clear、route:clear、view:clear、clear-compiled - 别只跑
config:clear——view:clear尤其关键,因为asset()辅助函数在编译后的视图中是硬编码逻辑
Web 服务器用户无权读取 storage/app/public
链接和缓存都对了,但 ls -la storage/app/public 显示属主是 root:root 或权限是 750,Nginx/Apache 就读不了。宝塔用户尤其要注意:PHP 实际运行用户未必是 www,得去 php-fpm 配置里确认 user = 和 group =。
- 查当前 Web 用户:
ps aux | grep php-fpm | grep -v grep或看宝塔 → 网站 → PHP 设置 → 配置文件中的user行 - 改归属(以
www为例):sudo chown -R www:www storage/app/public - 设目录可进入:
find storage/app/public -type d -exec chmod 755 {} \;(缺x权限=进不去目录) - 验证是否生效:
sudo -u www cat storage/app/public/test.jpg 2>/dev/null || echo "fail"
上传代码没走 public 磁盘,导致文件存错位置
很多人以为 $request->file('img')->store('uploads') 就会存到 storage/app/public/,其实它默认走的是 filesystems.default(通常是 local),结果文件进了 storage/app/uploads/,而这个路径根本没被软链接暴露出去。
- 显式指定磁盘:
$request->file('img')->store('uploads', 'public') - 上传后立刻验证:
Storage::disk('public')->exists('uploads/test.jpg') - 别用
move()直传——它绕过 Laravel 文件系统,既不校验路径也不触发事件,排查时完全找不到痕迹
最易忽略的是:即使所有步骤都做了,如果项目部署在子目录(比如域名指向 public_html/,但 Laravel 完整项目在 public_html/laravel/),APP_URL 和 ASSET_URL 没配对,asset('storage/xxx.jpg') 还是会拼出多一层 /laravel 的路径。这时候不是修 storage,而是调 APP_URL。


















