

适用于 JavaScript 的 Amazon SDK v2 已终止支持。建议您迁移到 [适用于 JavaScript 的 Amazon SDK v3](https://docs.amazonaws.cn//sdk-for-javascript/v3/developer-guide/)。有关更多详情和如何迁移的信息，请参阅本[公告](https://www.amazonaws.cn/blogs//developer/announcing-end-of-support-for-aws-sdk-for-javascript-v2/)。

# 从浏览器将照片上传到 Amazon S3
<a name="s3-example-photo-album"></a>

![JavaScript code example that applies to browser execution](http://docs.amazonaws.cn/sdk-for-javascript/v2/developer-guide/images/browsericon.png)

**此浏览器脚本代码示例演示：**
+ 如何创建允许用户在 Amazon S3 桶中创建相册并将照片上传到相册中的浏览器应用程序。

## 情景
<a name="s3-example-photo-album-scenario"></a>

在本示例中，一个简单的 HTML 页面提供了基于浏览器的应用程序，该应用程序在 Amazon S3 桶中创建相册，您可将照片上传到其中。通过该应用程序，您可以删除所添加的照片和相册。

![浏览器脚本中的 JavaScript，它将 Amazon S3 桶用于存储相册。](http://docs.amazonaws.cn/sdk-for-javascript/v2/developer-guide/images/images_bjs/s3-photo-album-example.png)


浏览器脚本使用 SDK for JavaScript 与 Amazon S3 桶交互。使用 Amazon S3 客户端类的以下方法来启用相册应用程序：
+ [https://docs.amazonaws.cn/AWSJavaScriptSDK/latest/AWS/S3.html#listObjects-property](https://docs.amazonaws.cn/AWSJavaScriptSDK/latest/AWS/S3.html#listObjects-property)
+ [https://docs.amazonaws.cn/AWSJavaScriptSDK/latest/AWS/S3.html#headObject-property](https://docs.amazonaws.cn/AWSJavaScriptSDK/latest/AWS/S3.html#headObject-property)
+ [https://docs.amazonaws.cn/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property](https://docs.amazonaws.cn/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property)
+ [https://docs.amazonaws.cn/AWSJavaScriptSDK/latest/AWS/S3.html#upload-property](https://docs.amazonaws.cn/AWSJavaScriptSDK/latest/AWS/S3.html#upload-property)
+ [https://docs.amazonaws.cn/AWSJavaScriptSDK/latest/AWS/S3.html#deleteObject-property](https://docs.amazonaws.cn/AWSJavaScriptSDK/latest/AWS/S3.html#deleteObject-property)
+ [https://docs.amazonaws.cn/AWSJavaScriptSDK/latest/AWS/S3.html#deleteObjects-property](https://docs.amazonaws.cn/AWSJavaScriptSDK/latest/AWS/S3.html#deleteObjects-property)

## 先决条件任务
<a name="s3-example-photo-album-scenario-prerequisites"></a>

要设置和运行此示例，您必须先完成以下任务：
+ 在 [Amazon S3 控制台](https://console.amazonaws.cn/s3/)中，创建一个 Amazon S3 桶，您将使用它在相册中存储照片。有关在控制台中创建桶的更多信息，请参阅《Amazon Simple Storage Service 用户指南》**中的[创建桶](https://docs.amazonaws.cn/AmazonS3/latest/userguide/create-bucket.html)。确保您同时拥有**对象**的**读取**和**写入**权限。有关设置桶权限的更多信息，请参阅[设置访问网站的权限](https://docs.amazonaws.cn/AmazonS3/latest/userguide/WebsiteAccessPermissionsReqd.html)。
+ 在 [Amazon Cognito 控制台](https://console.amazonaws.cn/cognito/)中，使用联合身份创建 Amazon Cognito 身份池，其中包含为与 Amazon S3 桶位于相同区域中的未验证身份用户启用的访问权限。您需要在代码中包含身份池 ID 以获取浏览器脚本的凭证。有关 Amazon Cognito 联合身份的更多信息，请参阅《Amazon Cognito 开发人员指南》**中的 [Amazon Cognito 身份池（联合身份）](https://docs.amazonaws.cn/cognito/latest/developerguide/cognito-identity.html)。
+ 在 [IAM 控制台](https://console.amazonaws.cn/iam/)中，查找 Amazon Cognito 针对未验证身份用户创建的 IAM 角色。添加以下策略，授予对 Amazon S3 桶的读取和写入权限。有关创建 IAM 角色的更多信息，请参阅《IAM 用户指南》**中的[创建向 Amazon 服务委派权限的角色](https://docs.amazonaws.cn/IAM/latest/UserGuide/id_roles_create_for-service.html)。

  为 Amazon Cognito 针对未验证身份用户创建的 IAM 角色使用此角色策略。
**警告**  
如果对未经身份验证的用户启用访问权限，您将向所有人授予对该存储桶及存储桶中的所有对象的写入访问权限。在本示例中，此安全状况很有用，可使其专注于示例的主要目标。但是，在许多实际情况下，强烈建议提高安全性（如使用经身份验证的用户和对象所有权）。

------
#### [ JSON ]

****  

  ```
  {
     "Version":"2012-10-17",		 	 	 
     "Statement": [
        {
           "Effect": "Allow",
           "Action": [
              "s3:DeleteObject",
              "s3:GetObject",
              "s3:ListBucket",
              "s3:PutObject",
              "s3:PutObjectAcl"
           ],
           "Resource": [            
              "arn:aws:s3:::{{BUCKET_NAME}}",
              "arn:aws:s3:::{{BUCKET_NAME}}/*"
           ]
        }
     ]
  }
  ```

------

## 配置 CORS
<a name="s3-example-photo-album-cors-configuration"></a>

在浏览器脚本可以访问 Amazon S3 桶之前，您必须先按以下所示设置其 [CORS 配置](cors.md#configuring-cors-s3-bucket)。

**重要**  
在新的 S3 控制台中，CORS 配置必须是 JSON。

------
#### [ JSON ]

```
[
    {
        "AllowedHeaders": [
            "*"
        ],
        "AllowedMethods": [
            "HEAD",
            "GET",
            "PUT",
            "POST",
            "DELETE"
        ],
        "AllowedOrigins": [
            "*"
        ],
        "ExposeHeaders": [
            "ETag"
        ]
    }
]
```

------
#### [ XML ]

```
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <AllowedMethod>HEAD</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
        <ExposeHeader>ETag</ExposeHeader>
    </CORSRule>
</CORSConfiguration>
```

------

## 网页
<a name="s3-example-photo-album-html"></a>

照片上传应用程序的 HTML 包含一个 <div> 元素，浏览器脚本在其中创建上传用户界面。第一个 <script> 元素将开发工具包添加到浏览器脚本。第二个 <script> 元素添加外部 JavaScript 文件，该文件保存浏览器脚本代码。

```
<!DOCTYPE html>
<html>
  <head>
     <!-- **DO THIS**: -->
    <!--   Replace SDK_VERSION_NUMBER with the current SDK version number -->
    <script src="https://sdk.amazonaws.com/js/aws-sdk-SDK_VERSION_NUMBER.js"></script>
    <script src="./s3_photoExample.js"></script>
    <script>
       function getHtml(template) {
          return template.join('\n');
       }
       listAlbums();
    </script>
  </head>
  <body>
    <h1>My Photo Albums App</h1>
    <div id="app"></div>
  </body>
</html>
```

## 配置 SDK
<a name="s3-example-photo-album-configure-sdk"></a>

通过调用 `CognitoIdentityCredentials` 方法并提供 Amazon Cognito 身份池 ID，获取配置 SDK 时所需的凭证。接下来，创建 `AWS.S3` 服务对象。

```
var albumBucketName = "BUCKET_NAME";
var bucketRegion = "REGION";
var IdentityPoolId = "IDENTITY_POOL_ID";

AWS.config.update({
  region: bucketRegion,
  credentials: new AWS.CognitoIdentityCredentials({
    IdentityPoolId: IdentityPoolId,
  }),
});

var s3 = new AWS.S3({
  apiVersion: "2006-03-01",
  params: { Bucket: albumBucketName },
});
```

此示例中几乎所有剩余的代码组织成一系列函数，这些函数收集并提供存储桶中相册的相关信息，上传并显示上传到相册中的照片，以及删除照片和相册。这些函数包括：
+ `listAlbums`
+ `createAlbum`
+ `viewAlbum`
+ `addPhoto`
+ `deleteAlbum`
+ `deletePhoto`

## 列出存储桶中的相册
<a name="s3-example-photo-album-list-albums"></a>

应用程序在 Amazon S3 桶中将相册创建为对象，其键以正斜杠字符开头，指示该对象用作文件夹。为列出存储桶中的所有现有相册，应用程序的 `listAlbums` 函数在使用 `listObjects` 时调用 `AWS.S3` 服务对象的 `commonPrefix` 方法，因此调用仅返回用作相册的对象。

函数的剩余部分从 Amazon S3 桶获取相册列表，并生成在网页中显示相册列表所需的 HTML。它还支持删除和打开单独的相册。

```
function listAlbums() {
  s3.listObjects({ Delimiter: "/" }, function (err, data) {
    if (err) {
      return alert("There was an error listing your albums: " + err.message);
    } else {
      var albums = data.CommonPrefixes.map(function (commonPrefix) {
        var prefix = commonPrefix.Prefix;
        var albumName = decodeURIComponent(prefix.replace("/", ""));
        return getHtml([
          "<li>",
          "<span onclick=\"deleteAlbum('" + albumName + "')\">X</span>",
          "<span onclick=\"viewAlbum('" + albumName + "')\">",
          albumName,
          "</span>",
          "</li>",
        ]);
      });
      var message = albums.length
        ? getHtml([
            "<p>Click on an album name to view it.</p>",
            "<p>Click on the X to delete the album.</p>",
          ])
        : "<p>You do not have any albums. Please Create album.";
      var htmlTemplate = [
        "<h2>Albums</h2>",
        message,
        "<ul>",
        getHtml(albums),
        "</ul>",
        "<button onclick=\"createAlbum(prompt('Enter Album Name:'))\">",
        "Create New Album",
        "</button>",
      ];
      document.getElementById("app").innerHTML = getHtml(htmlTemplate);
    }
  });
}
```

## 在存储桶中创建相册
<a name="s3-example-photo-album-create-album"></a>

为在 Amazon S3 桶中创建相册，应用程序的 `createAlbum` 函数首先验证为新相册提供的名称，确保它包含合适的字符。然后，函数构成 Amazon S3 对象键，将其传递到 Amazon S3 服务对象的 `headObject` 方法。此方法返回指定键的元数据，因此如果它返回数据，则具有该键的对象已存在。

如果相册尚不存在，则函数调用 `putObject` 服务对象的 `AWS.S3` 方法来创建相册。然后，它调用 `viewAlbum` 函数以显示新的空相册。

```
function createAlbum(albumName) {
  albumName = albumName.trim();
  if (!albumName) {
    return alert("Album names must contain at least one non-space character.");
  }
  if (albumName.indexOf("/") !== -1) {
    return alert("Album names cannot contain slashes.");
  }
  var albumKey = encodeURIComponent(albumName);
  s3.headObject({ Key: albumKey }, function (err, data) {
    if (!err) {
      return alert("Album already exists.");
    }
    if (err.code !== "NotFound") {
      return alert("There was an error creating your album: " + err.message);
    }
    s3.putObject({ Key: albumKey }, function (err, data) {
      if (err) {
        return alert("There was an error creating your album: " + err.message);
      }
      alert("Successfully created album.");
      viewAlbum(albumName);
    });
  });
}
```

## 查看相册
<a name="s3-example-photo-album-viewing-album"></a>

为显示 Amazon S3 桶中相册的内容，应用程序的 `viewAlbum` 函数获取相册名称并为该相册创建 Amazon S3 键。然后，函数调用 `listObjects` 服务对象的 `AWS.S3` 方法，获取相册中所有对象（照片）的列表。

函数的剩余部分从相册获取对象（照片）列表并生成在网页中显示照片所需的 HTML。它还支持删除单独的照片以及导航回相册列表。

```
function viewAlbum(albumName) {
  var albumPhotosKey = encodeURIComponent(albumName) + "/";
  s3.listObjects({ Prefix: albumPhotosKey }, function (err, data) {
    if (err) {
      return alert("There was an error viewing your album: " + err.message);
    }
    // 'this' references the AWS.Response instance that represents the response
    var href = this.request.httpRequest.endpoint.href;
    var bucketUrl = href + albumBucketName + "/";

    var photos = data.Contents.map(function (photo) {
      var photoKey = photo.Key;
      var photoUrl = bucketUrl + encodeURIComponent(photoKey);
      return getHtml([
        "<span>",
        "<div>",
        '<img style="width:128px;height:128px;" src="' + photoUrl + '"/>',
        "</div>",
        "<div>",
        "<span onclick=\"deletePhoto('" +
          albumName +
          "','" +
          photoKey +
          "')\">",
        "X",
        "</span>",
        "<span>",
        photoKey.replace(albumPhotosKey, ""),
        "</span>",
        "</div>",
        "</span>",
      ]);
    });
    var message = photos.length
      ? "<p>Click on the X to delete the photo</p>"
      : "<p>You do not have any photos in this album. Please add photos.</p>";
    var htmlTemplate = [
      "<h2>",
      "Album: " + albumName,
      "</h2>",
      message,
      "<div>",
      getHtml(photos),
      "</div>",
      '<input id="photoupload" type="file" accept="image/*">',
      '<button id="addphoto" onclick="addPhoto(\'' + albumName + "')\">",
      "Add Photo",
      "</button>",
      '<button onclick="listAlbums()">',
      "Back To Albums",
      "</button>",
    ];
    document.getElementById("app").innerHTML = getHtml(htmlTemplate);
  });
}
```

## 将照片添加到相册
<a name="s3-example-photo-album-adding-photos"></a>

为将照片上传到 Amazon S3 桶中的相册，应用程序的 `addPhoto` 函数在网页中使用文件选取器元素来标识要上传的文件。然后，它从当前相册名称和文件名，为上传的照片构成一个键。

函数调用 Amazon S3 服务对象的 `upload` 方法来上传照片。上传照片后，函数将重新显示相册，这样上传的照片会显示。

```
function addPhoto(albumName) {
  var files = document.getElementById("photoupload").files;
  if (!files.length) {
    return alert("Please choose a file to upload first.");
  }
  var file = files[0];
  var fileName = file.name;
  var albumPhotosKey = encodeURIComponent(albumName) + "/";

  var photoKey = albumPhotosKey + fileName;

  // Use S3 ManagedUpload class as it supports multipart uploads
  var upload = new AWS.S3.ManagedUpload({
    params: {
      Bucket: albumBucketName,
      Key: photoKey,
      Body: file,
    },
  });

  var promise = upload.promise();

  promise.then(
    function (data) {
      alert("Successfully uploaded photo.");
      viewAlbum(albumName);
    },
    function (err) {
      return alert("There was an error uploading your photo: ", err.message);
    }
  );
}
```

## 删除照片
<a name="s3-example-photo-album-delete-photo"></a>

为从 Amazon S3 桶的相册中删除照片，应用程序的 `deletePhoto` 函数将调用 Amazon S3 服务对象的 `deleteObject` 方法。这会删除传递到函数的 `photoKey` 值指定的照片。

```
function deletePhoto(albumName, photoKey) {
  s3.deleteObject({ Key: photoKey }, function (err, data) {
    if (err) {
      return alert("There was an error deleting your photo: ", err.message);
    }
    alert("Successfully deleted photo.");
    viewAlbum(albumName);
  });
}
```

## 删除相册
<a name="s3-example-photo-album-delete-album"></a>

为删除 Amazon S3 桶中的相册，应用程序的 `deleteAlbum` 函数将调用 Amazon S3 服务对象的 `deleteObjects` 方法。

```
function deleteAlbum(albumName) {
  var albumKey = encodeURIComponent(albumName) + "/";
  s3.listObjects({ Prefix: albumKey }, function (err, data) {
    if (err) {
      return alert("There was an error deleting your album: ", err.message);
    }
    var objects = data.Contents.map(function (object) {
      return { Key: object.Key };
    });
    s3.deleteObjects(
      {
        Delete: { Objects: objects, Quiet: true },
      },
      function (err, data) {
        if (err) {
          return alert("There was an error deleting your album: ", err.message);
        }
        alert("Successfully deleted album.");
        listAlbums();
      }
    );
  });
}
```