通过评论中的讨论,我得出了一些我想分享的要点。
Pre-Signed URLs
正如@ceejayoz 指出的那样,pre-signed
URL 不是一个坏主意,因为:
- 我可以将时间保持在 10 秒之内,这对于任何重定向和开始下载来说都是完美的,但不足以共享链接。
- 我之前的理解是下载必须在给定的时间内完成。因此,如果链接在 10 秒后过期,则必须在此之前进行下载。但@ceejayoz 指出事实并非如此。允许完成已开始的下载。
- With
cloud front
,我还可以限制IP地址,以增加更多的安全性。
IAM Roles
他还指出了另一个不太好的方法- 创建临时 IAM 用户。如果做得不正确,这将是一场维护噩梦,因此只有在您知道自己在做什么的情况下才可以这样做。
Stream From S3
这是我现在选择的方法。也许稍后我会转向第一种方法。
Warning:如果您进行流式传输,那么您的服务器仍然是中间人,所有数据都将通过您的服务器传输。因此,如果失败或速度缓慢,您的下载就会很慢。
我的第一个问题是 how to register stream wrapper
:
由于我使用 Laravel 并且 laravel 使用 Flysystem 进行 S3 管理,因此我没有简单的方法来获取 S3Client。因此我添加了额外的包AWS SDK for Laravel
in my composer.json
"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}");
}
}
我的第二个问题是 Do I need to Disable output buffering
在拉拉维尔?
恕我直言,答案是肯定的。缓冲使数据立即从缓冲区中刷新,从而降低内存消耗。由于我们没有使用任何 Laravel 函数将数据卸载到客户端,因此这不是由 Laravel 完成的,因此需要我们来完成。