从评论中的讨论中,我得出了一些我想分享的关键点。
Pre-Signed URLs
正如@ceejayoz 指出的那样,pre-signed
URL 不是一个坏主意,因为:
- 我可以将时间保持在 10 秒,这对于任何重定向和开始下载来说都是完美的,但不足以共享链接。
- 我之前的理解是下载必须在给定的时间内完成。因此,如果链接在 10 秒后过期,则必须在此之前进行下载。但@ceejayoz 指出事实并非如此。允许完成已开始的下载。
- 使用
cloud front
,我还可以限制 IP 地址,以增加安全性。
IAM Roles
他还指出了另一种不太好的方法——创建临时 IAM 用户。如果没有正确完成,这将是一场维护噩梦,所以只有在您知道自己在做什么的情况下才这样做。
Stream From S3
这是我目前选择的方法。也许稍后我会转向第一种方法。
警告:如果您流式传输,那么您的服务器仍然是中间人,所有数据都将通过您的服务器。因此,如果它失败或速度很慢,您的下载速度就会很慢。
我的第一个问题是 how to register stream wrapper
:
由于我使用 Laravel 并且 laravel 使用 flysystem 进行 S3 管理,所以我没有简单的方法来获取 S3Client。因此我AWS SDK for Laravel
在我的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 函数将数据卸载到客户端,这不是 laravel 完成的,因此需要由我们完成。