zoukankan      html  css  js  c++  java
  • 云盘上使用aws_s3_sdk for php

    aws s3 全名是 Simple Storage Service,是对象存储服务(oss),对象存储服务作为网盘的优点这里就不细说了,其提供的统一接口sdk几乎涵盖了所有语言。除了通用性以外,其以上传下载为核心的接口几乎可以满足所有的业务需求。本人在几年的工作中对接过不同sdk的接口,可以说aws s3的接口,只有你想不到,没有他做不到,虽然前提是你能从他那天书一样的接口文档中找到你想要的内容。下文是记录下对接过程中s3几个比较重要的接口,对象存储是私有化部署,下文代码是以php为开发语言(哪个开发语言不重要,只要语言底层支持io多路复用性能上都不会有太大区别)。

     

    连接

    access_key和secret_key是每个对象存储都会提供的信息,在endpoint填写自己私有化部署或者其它云服务商的对象存储地址

    use AwsS3S3Client;
    use AwsCredentialsCredentials;
    use AwsExceptionAwsException;
    use AwsExceptionMultipartUploadException;
    use AwsS3ObjectUploader;
    use AwsS3MultipartUploader;
    
    $this->client = new S3Client([
        'endpoint' => $endpoint,
        'region' => 'us-east-1', //需要随便一个region
        'service_name' => 's3',
        'verify' => 'False',
        'credentials' => new Credentials($aws_access_key_id, $aws_secret_access_key);,
        'version' => 'latest'
    ]);
    

    上传

    1、实现简单的文件上传

    $uploader = new ObjectUploader(
        $this->client,
        $bucket,
        $key,
        $source
    );
    $result = $uploader->upload();
    

    2、分片上传

    如果文件较大,上传时间会变慢,而且代码会堵塞在upload部分,

    所以可以通过接口提供分片上传:

    $source = '/path/to/large/file.zip';
    $uploader = new MultipartUploader($s3Client, $source, [
        'bucket' => 'your-bucket',
        'key' => 'my-file.zip',
        'before_initiate' => function (AwsCommand $command) {
            $command['CacheControl'] = 'max-age=3600';
        }
    ]);
    

    大致原理是对一个文件进行切割,然后并发上传,该方法有多个参数,可控制每个分片的大小,同时上传的分片数量或者每个分片上传前、上传后、上传失败等回调操作,十分灵活。

     

    3、异步分片上传

    虽然上面的分片上传操作可减少大文件上传时间,但是像一些上传文件的操作,从web端上传到服务端,需要先上传整个文件到服务端,然后服务端再上传文件到oss端。这样的话如果服务端使用oss做文件存储,就算web端使用了分片上传到服务端,服务端也得等待所有分片上传完毕,合成最终文件,再将文件上传到oss端,这样上传时间会变多。所以要优化分片上传的操作,可以使用s3提供的异步分片上传功能:

    $res = $this->client->createMultipartUpload(array_merge([
        'Bucket' => $bucket, // REQUIRED
        'Key' => $key, // REQUIRED
        'Expires' => $expire,
    ], $args));
    return $res;
    

    上面代码提供了一个分片上传任务,并返回一个upload_id,这样当web端上传了一个文件的分片,可根据upload_id先上传到oss端,oss端将分片暂时保存到内存中(需要根据分片顺序填写PartNumber):

    $res = $this->client->uploadPart([
        'Body' => $source,
        'Bucket' => $bucket, // REQUIRED
        'Key' => $key, // REQUIRED
        'PartNumber' => $PartNumber, // REQUIRED
        'UploadId' => $UploadId, // REQUIRED
    ]);
    return $res;
    

    当web端所有分片都上传完毕,同时所有分片也上传到oss端后,调用完成上传接口:

    $res = $this->client->completeMultipartUpload([
        'Bucket' => $bucket, // REQUIRED
        'Key' => $key, // REQUIRED
        'MultipartUpload' => $MultipartUpload,
        'UploadId' => $UploadId, // REQUIRED
    ]);
    return $res;
    

    这样就能实现web端上传与服务端上传oss的并发进行,可节省大量的上传时间。

    上面是上传的主要功能,每个接口还提供了大量的参数和回调方法,主要很多参数和回调现在也没有需求用得上,在此就不一一列举

     

    下载

    php sdk的下载功能比起python来说功能比较简陋,但也可以实现分片下载功能,涉及到下载文件的只有一个接口:

    $res = $this->client->getObject(array_merge([
        'Bucket' => $bucket,
        'Key' => $key,
        'Range' => 'bytes=0-9',
        'SaveAs' => '/path/to/save/file'
    ], $args));
    return $res;
    

    其中比较重要的是range参数,它实现了浏览器的断点续传功能,当浏览器请求文件下载时,如果文件存储在oss,普通情况下需要把文件先下载下来,然后再让浏览器分片下载,但是通过传递range参数,把文件对应的分片从oss下载下来,然后再发送给web端,实现了持续从oss端下载到web端,中间无阻隔

     

    分页查询

    普通的分页查询可使用listObjects:

    $result = $this->client->listObjects([
        'Bucket' => '<string>', // REQUIRED
        'Delimiter' => '<string>',
        'EncodingType' => 'url',
        'ExpectedBucketOwner' => '<string>',
        'Marker' => '<string>',
        'MaxKeys' => <integer>,
        'Prefix' => '<string>',
    ]);
    

    使用MaxKeys作为每页数量,Marker作为每次请求一页中的最后一个文件,作为key传给下一页请求的marker,类似offset的作用。

    实际上由于oss没有分页功能,普通这样的请求只能从第一页开始查询直到想查询的页数,浪费大量的资源。所以可以通过oss提供的分页迭代器来实现:

    $args['Bucket'] = $bucket;
    $args['MaxKeys'] = $limit;
    $results = $this->client->getPaginator('ListObjects', $args);
    $total_results = [];
    for ($i = 0; $i < $offset; $i++) {
        if ($results->valid()) {
            $results->next();
        } else {
            break;
        }
    }
    if ($results->valid()) {
        array_push($total_results, $results->current());
        $results->next();
    }
    return $total_results;
    

    迭代器是几乎所有语言都有实现的功能,他的作用是保存代码上下文状态,例如上面的代码,通过迭代器形成一个分页工具,当使用next进行翻页,底层代码不需要请求接口,而是通过指针指向下一页,这样就能实现快速翻页,获取对应页数的文件。

  • 相关阅读:
    Flink 源码(十一):阅读 Flink 源码前必会的知识(六)高性能异步编程 和 实时流模型关联
    Flink 源码(十):阅读 Flink 源码前必会的知识(五)SPI 和 ClassLoader(二) SPI 技术
    Flink 源码(九):阅读 Flink 源码前必会的知识(四)SPI 和 ClassLoader(一)ClassLoader
    Flink 源码(八):阅读 Flink 源码前必会的知识(三)Java 8 异步编程 CompletableFuture 全解析(三)
    Flink 源码(七):阅读 Flink 源码前必会的知识(二)Java 8 异步编程 CompletableFuture 全解析(二)
    Flink 源码(六):阅读 Flink 源码前必会的知识(一)Java 8 异步编程 CompletableFuture 全解析(一)
    GIT基础(二十四):Git 基本操作(十五)git push 命令
    GIT基础(二十三):Git 基本操作(十四)git pull 命令
    吴恩达机器学习CS229课程笔记学习
    KVM 虚机的创建过程
  • 原文地址:https://www.cnblogs.com/eflypro/p/14741936.html
Copyright © 2011-2022 走看看