Laravel API 路由需显式启用文件解析:确保 Content-Type 为 multipart/form-data,配置 PHP 上传限制,并避免先调用 $request->file() 导致 $_FILES 清空;验证应统一使用 validate(),存储用 store()/storeAs() 后通过 Storage::url() 返回可访问路径。

API 接口里怎么接收上传的文件
Laravel 的 API 路由默认不启用 session,也不解析 multipart/form-data 请求体里的文件——这会导致 $request->file() 返回 null,哪怕前端明明发了文件。
关键不是“怎么写上传逻辑”,而是“怎么让 Laravel 在无 session 的 API 场景下正确解析文件”。必须确保两点:
- 路由定义在
api.php中,但需显式启用文件解析中间件:Illuminate\Http\Middleware\ValidatePostSize和App\Http\Middleware\TrimStrings默认已加载,但真正起作用的是底层对$_FILES的读取,它依赖 PHP 的post_max_size和upload_max_filesize配置; - 请求头必须包含
Content-Type: multipart/form-data; boundary=...,且不能手动设置(浏览器或FormData会自动生成),否则 Laravel 根本不进文件解析流程。
常见错误现象:$request->hasFile('avatar') 永远返回 false,$request->file('avatar') 是 null,但 $request->all() 能看到其他字段——说明请求体被当成了普通 JSON 或表单编码处理了。
Laravel 10+ 中 store() 和 storeAs() 的路径差异
这两个方法看着像只是“存哪”的区别,实际影响文件可见性、磁盘配置和 URL 生成逻辑。
store() 把文件存在配置的默认磁盘根目录下(比如 public/ 或 storage/app/),返回相对路径(如 documents/abc.pdf);storeAs() 允许你指定完整子路径+文件名,但第一个参数是「目录」,第二个才是「文件名」,容易传反:
$path = $request->file('file')->storeAs('invoices', '2024-001.pdf'); // ✅
$path = $request->file('file')->storeAs('2024-001.pdf', 'invoices'); // ❌ 文件名变目录名
使用场景上:store() 适合不需要控制文件名的场景(如用哈希重命名);storeAs() 适合需要保留原始名或按业务规则组织路径的情况。但注意:如果磁盘是 public 类型,用 storeAs() 存到 public/uploads/ 下,还得运行 php artisan storage:link 才能通过 /storage/ URL 访问。
验证失败时,$request->file() 会丢失吗
会。Laravel 的验证器(validate() 或 validated())在失败时会抛出异常并终止执行,但更隐蔽的问题是:一旦调用过 $request->file(),PHP 的 $_FILES 数组会被清空(这是 PHP SAPI 层限制,非 Laravel 特有)。所以如果你先调用 $request->file('photo')->isValid() 做预检,再走 $request->validate(...),第二步的验证会因找不到文件而报 The photo must be a file.。
正确做法是只用一次验证入口,把文件规则写进 validate():
$request->validate([
'photo' => 'required|file|mimes:jpg,png|max:2048',
]);
不要拆成「先取再验」。另外,mimes 规则依赖 finfo_file(),某些容器环境(如 Alpine)可能没装 fileinfo 扩展,导致 mime 检查永远失败,报错信息却是 The photo failed to upload. —— 这时候要检查 PHP 扩展而非 Laravel 配置。
API 返回文件路径时,别直接拼 storage_path()
返回 storage_path('app/invoices/xxx.pdf') 这种本地绝对路径给前端,等于暴露服务器结构,也完全不可访问。正确路径取决于磁盘驱动:
- 用
public磁盘:存完后调用Storage::url('path/to/file.jpg'),返回/storage/path/to/file.jpg; - 用
s3磁盘:同样用Storage::url(),返回预签名或公开 URL; - 别用
Storage::path(),那是服务器内部路径,API 不该返回它。
容易被忽略的一点:如果用的是 local 磁盘但配置为 public 可见,仍需确保 public/storage 是软链到 storage/app/public,否则 Storage::url() 生成的路径 404。这个链接不是 Laravel 自动维护的,部署时漏掉就全挂了。


















