For the introduction of Aliyun OSS, please refer to the official document: Aliyun OSS.

For account security, the front-end use of OSS services requires temporary authorization, that is, a temporary certificate (STS Token) to call aliyun-OSS SDK. For information on temporary authorization, see: INTRODUCTION to RAM and STS, RAM subaccounts, AND STS Temporary Authorization to access OSS.

Taking NodeJs as an example, the implementation of the backend issuing temporary credentials to the front end can be seen in the Node STS authorization

For the operations related to uploading files to Aliyun on the front end, refer to uploading files on the browser side

After understanding the above concepts, the next step can go to the Ali Cloud OSS console for related Settings (provided that the OSS service is opened).

Ali Cloud OSS console configuration

1. Create a Bucket

First, we create a bucket, a container for storing files:

Next, we need to set the bucket to cross domains so that we can invoke the Aliyun OSS server interface from the web page:

2. Create a RAM user

Next, go to the RAM console to configure sub-accounts and permissions.

To start, we create a user and give the user permission to invoke the STS service AssumeRole interface so that the back end can later assign the STS credentials to the front end as the user:

We need to save the user’s Access key and access key secret, which the back end needs to verify the user’s identity.

3. Create the RAM role

This role is a user role that has permission to upload files using aliyun-oss SDK on the front end. For example, let’s create a role with only upload permission and name it uploader:

Next, you need to assign permissions to the role. You can create a permission policy and assign permissions to the role. The permission policy only includes the permissions related to file upload and fragment upload.

The specific contents of the policy are as follows:

{
  "Version": "1"."Statement": [{"Effect": "Allow"."Action": [
        "oss:PutObject"."oss:InitiateMultipartUpload"."oss:UploadPart"."oss:UploadPartCopy"."oss:CompleteMultipartUpload"."oss:AbortMultipartUpload"."oss:ListMultipartUploads"."oss:ListParts"]."Resource": [
        "acs:oss:*:*:mudontire-test"."acs:oss:*:*:mudontire-test/*"]]}}Copy the code

Then, assign the policy to the Uploader role:

This is the end of alicloud OSS background configuration. Next, let’s focus on the implementation of the front and back ends.

The backend implementation

Since the front end is responsible for the upload, the back end has a simple task of providing an STS Token to the front end. This article uses NodeJs as an example to implement the following.

1. Install the Aliyun-OSS SDK

npm install ali-oss
Copy the code

2. Generate the STS Token and return it

const OSS = require('ali-oss');
const STS = OSS.STS;

const sts = new STS({
  accessKeyId: process.env.ALIYUN_OSS_RULE_ASSUMER_ACCESS_KEY,
  accessKeySecret: process.env.ALIYUN_OSS_RULE_ASSUMER_ACCESS_KEY_SECRET
});

async function getCredential(req, res, next) {
  try {
    const { credentials } = await sts.assumeRole(
      'acs:ram::1582938330607257:role/uploader',  // role arn
      null, // policy
      15 * 60, // expiration
      'web-client'// session name ); req.result = credentials; next(); } catch (err) { next(err); }}Copy the code

The Access key and Access key secret are stored in the.env file. Assumption () returns the STS Token and accepts the four parameters: role arn, policy, expiration, session name.

Role arn can be obtained from the RAM Role details page:

Policy is a user-defined Policy. Since the permission Policy has been added for the role, null can be passed.

Expiration is the Expiration time of the STS Token. The Expiration time ranges from 15 minutes to 60 minutes. When the Token is invalid, the front-end needs to obtain the Token again.

Session name indicates a user-defined Session name.

The back-end implementation is complete!

The front-end implementation

The front-end implementation of this article uses native JS, and there are also ant Design Pro versions available on the Github project.

The front-end implementation has several key points:

  1. Obtain the STS Token before calling the Aliyun-OSS SDK
  2. Define the upload fragment size. If the file size is smaller than the fragment size, upload by normal. Otherwise, upload by fragment
  3. The upload progress is displayed during the upload process
  4. During the upload process, if the STS Token is about to expire, the system stops the upload to obtain the Token again, and then resumes the upload
  5. Supports manual pause and continuation
  6. After the upload is complete, return to the address where the file was downloaded

1. Introduce aliyun-OSS SDK

Refer to the introduction of aliyun-OSS SDK

2. HTML

HTML contains file selector, upload, pause, continue buttons, status display:

<div>
  <input type="file" id='fileInput' multiple='true'>
  <button id="uploadBtn" onclick="upload()">Upload</button>
  <button id="stopBtn" onclick="stop()">Stop</button>
  <button id="resumeBtn" onclick="resume()">resume</button>
  <h2 id='status'></h2>
</div>
Copy the code

3. Define variables

letcredentials = null; / / STS credentialsletossClient = null; // Oss client instance const fileInput = document.getelementById ()'fileInput'); Const status = document.getelementById ();'status'); // State display element const bucket ='mudontire-test'; // Bucket name const region ='oss-cn-shanghai'; // oss service region name const partSize = 1024 * 1024; Const parallel = 3; // Const parallel = 3; Const CAPTURE = {}; // Capture a const capture; // Check point for all fragments to upload filesCopy the code

4. Obtain the STS certificate and create an OSS Client

// Obtain the STS Tokenfunction getCredential() {
  return fetch('http://localhost:5050/api/upload/credential')
    .then(res => {
      returnres.json() }) .then(res => { credentials = res.result; }) .catch(err => { console.error(err); }); } // Create OSS Client asyncfunction initOSSClient() {
  const { AccessKeyId, AccessKeySecret, SecurityToken } = credentials;
  ossClient = new OSS({
    accessKeyId: AccessKeyId,
    accessKeySecret: AccessKeySecret,
    stsToken: SecurityToken,
    bucket,
    region
  });
}
Copy the code

5. Click upload button event

async function upload() {
  status.innerText = 'Uploading'; // Obtain STS Token await getCredential(); const { files } = fileInput; const fileList = Array.from(files); Const uploadTasks = filelist.foreach (file => {// If the file size is smaller than the fragment size, use normal upload, otherwise use fragment uploadif (file.size < partSize) {
      commonUpload(file);
    } else{ multipartUpload(file); }}); }Copy the code

6. Normal upload

// Common upload asyncfunction commonUpload(file) {
  if(! ossClient) { await initOSSClient(); } const fileName = file.name;return ossClient.put(fileName, file).then(result => {
    console.log(`Common upload ${file.name} succeeded, result === `, result)
  }).catch(err => {
    console.log(`Common upload ${file.name} failed === `, err);
  });
}
Copy the code

7. Upload fragments

// Fragment upload asyncfunction multipartUpload(file) {
  if(! ossClient) { await initOSSClient(); } const fileName = file.name;returnossClient.multipartUpload(fileName, file, { parallel, partSize, progress: OnMultipartUploadProgress}). Then (result = > {/ / generated const url = ` http:// file download address${bucket}.${region}.aliyuncs.com/${fileName}`;
    console.log(`Multipart upload ${file.name} succeeded, url === `, url)
  }).catch(err => {
    console.log(`Multipart upload ${file.name} failed === `, err);
  });
}
Copy the code

9. Resumable transmission

// Break to continue asyncfunction resumeMultipartUpload() {
  Object.values(checkpoints).forEach((checkpoint) => {
    const { uploadId, file, name } = checkpoint;
    ossClient.multipartUpload(uploadId, file, {
      parallel,
      partSize,
      progress: onMultipartUploadProgress,
      checkpoint
    }).then(result => {
      console.log('before delete checkpoints === ', checkpoints);
      delete checkpoints[checkpoint.uploadId];
      console.log('after delete checkpoints === ', checkpoints);
      const url = `http://${bucket}.${region}.aliyuncs.com/${name}`;
      console.log(`Resume multipart upload ${file.name} succeeded, url === `, url)
    }).catch(err => {
      console.log('Resume multipart upload failed === ', err);
    });
  });
}
Copy the code

10. Fragment upload progress

In the progress callback, we can determine whether the STS Token is about to expire. If it is about to expire, we will cancel the upload and get a new Token before continuing the transmission from the previous break point.

// Fragment upload progress change callback asyncfunction onMultipartUploadProgress(progress, checkpoint) {
  console.log(`${checkpoint.file.name}Upload progress${progress}`); checkpoints[checkpoint.uploadId] = checkpoint; // Check whether the STS Token is about to expire. When the STS Token expires, obtain const {Expiration} = credentials again. const timegap = 1;if (Expiration && moment(Expiration).subtract(timegap, 'minute').isBefore(moment())) {
    console.log(`STS token will expire in ${timegap}Minutes, uploading will pause and resume after getting new STS tokens);if(ossClient) { ossClient.cancel(); } await getCredential(); await resumeMultipartUpload(); }}Copy the code

11. Pause and Resume button click events

// Pause the uploadfunction stop() {
  status.innerText = 'Stopping';
  if(ossClient) ossClient.cancel(); } / / continuinglyfunction resume() {
  status.innerText = 'Resuming';
  if (ossClient) resumeMultipartUpload();
}
Copy the code

Github sample project

Project address: github.com/MudOnTire/a…