本次对接文件上传,目标是实现超级大文件的上传任务,可能就是4~5个g的视频文件,折腾了蛮久熟悉s3,因此记录一下。
大家要是对filesystem不清楚去看一下官方文档不然可能有点懵逼。
首先我先是对接了一个普通的s3存储文件的功能,但是这个不能存储太大的文件。
upload:
private function uploadToS3()
{
try {
$request = request();
$file = $request->file('image_files');
$name = md5(uniqid(md5(microtime(true)), true)) . '.' . $file->getClientOriginalExtension();
$recPath = Storage::disk('s3')->put($name, file_get_contents($file));
if ($recPath) {
$recUrl = Storage::disk('s3')->url($name);
return ['url'=>$recUrl,'name'=>$name,'$recPath'=>$recPath];
}
} catch (\Exception $e) {
throw new CustomException($e->getMessage());
}
}
$recPath = Storage::disk('s3')->put($name, file_get_contents($file)); 中Storage::disk('s3')意思就是采用s3的存储引擎,然后直接put到s3的存储桶里面。因为laravel自带的filesystem提供了对s3的支持,因此可以便捷地使用s3。
当然就这个方法还不够,还需要我们配置好才可以。
我们需要进入到filesystems.php文件下面,进行配置
由于默认使用的本地驱动
因此我们要用s3就必须带上Storage::disk('s3')
env是全局变量,是.env文件里面配置好了地参数
其实laravel简单接入s3的存储很简单,只需要配置好,然后调用即可访问。当然,控制台那边的存储同需要可以被公共访问才可以,下面会讲到。
将上面的事情做完就可以实现上传文件并且访问。不过这种方法并不支持大文件,文件过大就会报错:
下面就是实现大文件上传的方法步骤。
一般来说,大文件上传大家会采取分片上传,续点上传的方式,不过我这次没有使用哪种方式。我使用的是aws 提供的一种由前端直接上传文件至S3的方式.
此方法由AWS提供,它不仅能是上传速度更快,且同时支持上传大文件,AWS的JSSDK已经封装好了,我们只需要拿来用就行,架构如下:
包含有对接实例的官方文档:Uploading to Amazon S3 directly from a web or mobile application | AWS Compute Blog
其实大概思路就是,后端先通过访问aws的接口获取到一个加权url并且返回给前端。使用预签名 URL 上传对象 - Amazon Simple Storage Service
有了加权的url前端就可以直接使用这个加权的url来进行文件的上传,并且我亲自测试,上传2,3个g的文件也不会出问题。然后我们直接把访问路径获取到返回给前端进行访问。这么一看是不是比分片上传还要方便?
中间的中间的web client,seq Auth,User service大家可以直接看作后端服务器。
首先先找到AWS SDK for PHP的操作文档,先按照文档的安装把包导进来以便可以使用aws官方的api。然后参照预签名示例来写代码。
使用 AWS SDK for PHP 版本 3 的 Amazon S3 预签名 URL - AWS SDK for PHP
private function uploadToS3()
{
$fileName = request()->input('file_name');
$bucket = 'xxxxxxxxxxxxx';
$expiration = '+1 hour';
$s3Client = new S3Client([
'version' => 'latest',
'region' => 'xxxxxxxxx',
'credentials' => [
'key' => 'xxxxxxxxx',
'secret' => 'xxxxxxxxxxx',
],
]);
$presignedUrl = $s3Client->getCommand('PutObject', [
'Bucket' => $bucket,
'Key' => $fileName,
'Content-Type'=>'video/mp4'
]);
$getObjectUrl = $s3Client->getObjectUrl($bucket, $fileName);
$request = $s3Client->createPresignedRequest($presignedUrl, $expiration);
$presignedUrl = (string)$request->getUri();
return ['s3Url' => $presignedUrl, 'url' => $getObjectUrl];
}
大家执行替换代码中的xxxx部分。
然后就是getCommand第一个参数其实就是选择api的作用,以下是可以选择的参数
其实挺明显的,选了PutObject,得到的s3Url就是用来上传的,GetObject则是获取的url(如果你的s3存储同是允许共有访问的,你就可以直接通过返回的url进行访问,否则只能通过s3Url进行访问)。
测试:
然后我直接拿着s3Url去发送Put请求
一定得是PUT请求,并且文件是binary而不是form-data,这个需要注意!!
然后我直接拿着开始upload给的url去访问
再次提醒,你得存储同权限需要是可共有访问得!!
策略这里添加
{
"Version": "2012-10-17",
"Id": "S3PolicyId1",
"Statement": [
{
"Sid": "Statement1",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucketName/*"
}
]
}
跨域这里添加
[
{
"AllowedHeaders": [],
"AllowedMethods": [
"GET"
],
"AllowedOrigins": [
"*"
],
"ExposeHeaders": []
}
]
全部弄好之后基本上可以上传成功并且访问。
当然还有种情况就是,视频成功上传,也可以访问,但是它是直接下载而不是可以直接观看,这里可以借鉴这个文章
Solved: Video On Amazon S3 Downloading Instead of Playing – TechBasedMarketing
就是桶里面对象得元数据,需要是这个格式才行,不然访问url,视频就是下载而不是播放了。