加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 资源网站 > 资源 > 正文

使用Laravel从Web服务器流式传输Amazon S3对象

发布时间:2020-12-14 22:33:56 所属栏目:资源 来源:网络整理
导读:在我使用laravel 5.1构建的web应用程序中,用户可以上传我存储在Amazon S3中的一些敏感文件.后来我希望用户WITH PERMISSION下载此文件.由于我希望进行此身份验证检查,因此我无法使用传统方法下载该文件,只需在S3中直接链接到文件即可. 我的方法: 当用户请求
在我使用laravel 5.1构建的web应用程序中,用户可以上传我存储在Amazon S3中的一些敏感文件.后来我希望用户WITH PERMISSION下载此文件.由于我希望进行此身份验证检查,因此我无法使用传统方法下载该文件,只需在S3中直接链接到文件即可.

我的方法:

>当用户请求下载时,我的服务器在本地下载文件,然后流式传输给用户.问题:需要很长时间,因为文件有时太大.
>为用户提供预先签名的URL,以便直接从S3下载. URL仅在5分钟内有效.问题:如果共享该URL,则任何人都可以在5分钟内下载该URL.
> According to this article,将数据直接从S3流式传输到客户端.这看起来很有希望,但我不知道如何实现这一点.

根据这篇文章,我需要:

>注册流包装 – 这是我的第一个问题,因为我不知道如何获取S3Client对象,因为laravel使用flysystem,我不知道调用什么方法来获取这个对象.也许我需要在我的composer.json中单独包含S3包?
>禁用输出缓冲 – 我是否需要在laravel中执行此操作或laravel是否已经处理过它?

我相信其他开发人员之前已经看过这样的问题,并希望得到一些帮助指针.如果有人已经使用laravel Response :: download($pathToFile,$name,$headers)直接从S3流向客户端,那么我很想听听你的方法.

解决方法

通过评论中的讨论,我得出了一些我想分享的关键点.

预签名网址

正如@ceejayoz指出的那样,预先签名的URL并不是一个坏主意,因为:

>我可以保持时间低至10秒,这对于任何重定向和开始下载都是完美的,但不足以让链接被共享.
>我之前的理解是下载必须在给定的时间内完成.因此,如果链接在10秒内到期,则必须在此之前进行下载.但@ceejayoz指出事实并非如此.已启动的下载允许完成.
>借助云前端,我还可以限制IP地址,以增加更多安全性.

IAM角色

他还指出了另一种不太好的方法 – 创建临时IAM用户.如果没有正确完成,这是一个维护噩梦,所以只有你知道自己在做什么才行.

来自S3的流

这是我现在选择的方法.也许以后我会转向第一种方法.

警告:如果您流式传输,那么您的服务器仍然是中间人,所有数据都将通过您的服务器传输.因此,如果它失败,或者速度很慢,那么下载速度会很慢.

我的第一个问题是如何注册流包装器:

由于我使用Laravel和laravel使用flysystem进行S3管理,因此我无法轻松获得S3Client.因此,我在composer.json中为Laravel添加了额外的包AWS SDK

"aws/aws-sdk-php-laravel" : "~3.0"

然后我写了我的代码如下:

class FileDelivery extends Command implements SelfHandling
{
    private $client;
    private $remoteFile;
    private $bucket;

    public function __construct($remoteFile)
    {
        $this->client = AWS::createClient('s3');
        $this->client->registerStreamWrapper();
        $this->bucket = 'mybucket';
        $this->remoteFile = $remoteFile;
    }

    public function handle()
    {
        try
        {
            // First get the meta-data of the object.
            $headers = $this->client->headObject(array(
                'Bucket' => $this->bucket,'Key' => $this->remoteFile
            ));

            $headers = $headers['@metadata'];
            if($headers['statusCode'] !== 200)
            {
                throw new S3Exception();
            }
        }
        catch(S3Exception $e)
        {
            return 404;
        }

        // return appropriate headers before the stream starts.
        http_response_code($headers['statusCode']);
        header("Last-Modified: {$headers['headers']['last-modified']}");
        header("ETag: {$headers['headers']['etag']}");
        header("Content-Type: {$headers['headers']['content-type']}");
        header("Content-Length: {$headers['headers']['content-length']}");
        header("Content-Disposition: attachment; filename="{$this->filename}"");

        // Since file sizes can be too large,// buffers can suffer because they cannot store huge amounts of data.
        // Thus we disable buffering before stream starts.
        // We also flush anything pending in buffer.
        if(ob_get_level())
        {
            ob_end_flush();
        }
        flush();

        // Start the stream.
        readfile("s3://{$this->bucket}/{$this->remoteFile}");
    }
}

我的第二个问题是我是否需要在laravel中禁用输出缓冲?

答案恕我直言是肯定的.缓冲使数据立即从缓冲区刷新,从而降低内存消耗.由于我们没有使用任何laravel函数将数据卸载到客户端,因此不能通过laravel完成,因此需要由我们完成.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读