Laravel 和 Vue.js 如何正确地处理文件上传?
上传文件的方式
大多数如何使用 JavaScript 上传文件的文章实际上都在讲如何用 Base64 对文件内容编码,以便可以将其包含在 JSON 请求中。虽然可以用,但是效率不如其他方法。在本文中,我将展示如何在 Vue.js 和 axios 中使用multipart/FormData 方法上传文件。
JSON 中的 Base64
优点:
- 不需要手动将数据编码/解码为 JSON 格式(如果使用任何前端框架或客户端库)
- 文件的内容只是 JSON 对象中的另一个字段
缺点:
- 需要在 Base64 中编码文件
- 使用更多的 CPU,更多的内存以及占用更多的网络带宽(Base64 使用的空间比二进制文件多 33%)
- 来自后端框架的支持很少
Multipart
优点:
- 不需要用Base64编码文件
- 使用更少的 CPU,更少的内存以及占用更少的网络带宽
- 来自后端框架的全面支持
缺点:
- 需要手动将数据编码/解码为 JSON 格式
- 文件的内容与 JSON 对象是分开的
获取文件
无论哪种方式,您的页面都将具有一个文件输入组件,该文件输入组件使用户可以选择文件。如果您尝试在 Vue 上使用 v-model
,Vue 会报错,因为文件输入是只读的,因此我们通常为 change
事件添加事件处理程序。
<template>
<input type="file" @change="selectFile">
</template>
<script>
data: () => ({
photo: null,
description: '',
productId: 0,
}),
methods: {
selectFile(event) {
// files 始终是数组,因为文件输入可能处于多种模式
this.photo = event.target.files[0];
}
}
</script>
发送文件
文件输入元素具有 files
属性,该属性是 File
类实例的数组。它拥有所选文件的一些元数据以及读取其内容的方法。除此之外,它可以直接用作FormData
对象中的值。FormData
类允许使用 JavaScript 构造与普通 HTML 表单创建的相同请求。使用 axios,jQuery 或者普通的XMLHttpRequest
对象时,可以将 FormData
对象用作请求的主体。
以下几点:
const data = new FormData();
data.append('photo', this.photo);
data.append('description', this.description);
data.append('productId', this.productId);
axios.post("/api/photo", data);
大致相当于:
<form method="POST" enctype="multipart/form-data" action="/api/photo">
<input type="file" name="photo"/>
<input type="text" name="description"/>
<input type="text" name="productId">
</form>
如果您将复杂数据作为数组或嵌套对象,则必须手动转换为 JSON:
const data = new FormData();
data.append('photo', this.photo);
const json = JSON.stringify({
description: this.description,
productId: this.productId,
});
data.append('data', json);
axios.post("/api/photo", data);
接收文件
在Laravel方面,完全支持使用 Request
类透明地处理文件上传。上载的文件是任何其他字段,框架将其作为 Illuminate\Http\UploadedFile
类的实例显示。从那里你可以读取文件的内容或将其存储在其他位置。
public function savePhoto(Request $request)
{
// 验证(大小以 KB 为单位)
$request->validate([
'photo' => 'required|file|image|size:1024|dimensions:max_width=500,max_height=500',
]);
// 读取文件内容
$contents = file_get_contents($request->photo->path());
// 或者只是将其移动到其他地方(例如:本地 storage 目录或 S3 )
$newPath = $request->photo->store('photos', 's3');
}
如果你具有手动转换为JSON的复杂数据,则需要在使用前对其进行解码:
public function savePhoto(Request $request)
{
$request['data'] = json_decode($request['data']);
// 验证
$request->validate([
'data.description' => 'required|filled|size:100',
'data.productId' => 'required|int|exists:App\Product,id'
]);
// 其余和上面代码相同
}
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
推荐文章: