Use Tencent cloud object cloud storage to upload files (Java temporary secret key) and use applet SDK

Upload files using Tencent cloud object cloud storage (Java temporary secret key)

Use the domain name that has been resolved by Tencent cloud DNS

  • Save - > test

Test access picture (uploaded...)

Using the Java SDK (mostly for developing desktop applications using Java)

Note: most of the Java SDK s are File object operations. Don't try to pass them to the java server and then to Cos. The pressure is too high, which will lose the original intention of COS. In addition, there are javascript SDK and applet SDK. Why bother to pressurize the server?

  • Required: API key, bucketName information, url information (domain name / provided by default)

API key https://console.cloud.tencent.com/cam/capi

😒 I realized after encapsulating my Utils that this is not a pure server-side pressurization tool class?

  • If you want to transfer files and record, js sdk or applet sdk calls api + java background api database field record

Therefore, if you are a desktop app, you can directly refer to the Java SDK, which is very simple. c + v is good

Use java to obtain the temporary secret key (main content)

If you are lazy and are not afraid of permanent secret key disclosure, you can directly find the corresponding SDK

  1. 1-2 applet | app | web = > our Java Server = > Tencent's CAM permission system is synchronized with our COS temporary secret key
  2. 3-4 cam = > java server = > applet |... (get the temporary secret key)
  3. 5. Carry the temporary secret key to request upload and download operations

Using the applet SDK

  • npm installation / npm build applet has problems. I also have applet build problems. The stupidest way is to download wx-cos-sdk-v5.js and then import it
npm install cos-wx-sdk-v5
  • introduce
const COS = require('cos-wx-sdk-v5');
  • Configure wechat applet whitelist

Because I haven't uploaded the background to the server yet, they are all tested locally, so they can be omitted here and can be configured later

Settings: wechat developer tool - > details in the upper right corner - > local settings - > local settings ✔ Do not verify the legal domain name... And HTTPS certificate

Official method 1 (recommended): the back end obtains the temporary key to the front end, and the front end calculates the signature

  1. QCloundController.java
    // Temporary key configuration
    TreeMap<String, Object> config = new TreeMap<String, Object>();
    Response credential = null; // Voucher result

    try {
      config.put("SecretId", cosProperties.getSecretId());
      config.put("SecretKey", cosProperties.getSecretKey());
      config.put("durationSeconds", 1800); // Set available events for 1800 seconds - > 30 minutes
      config.put("bucket", cosProperties.getBucketName()); // Bucket name
      config.put("region", cosProperties.getRegion()); // region
      // Resource = > prefix of policy
      // Access only allowed: [avatar / *]
      config.put("allowPrefixes", new String[] {
              cosProperties.getAvatarPrefix()
      });

      // List of permissions for the key. The permissions required for this temporary key must be specified here.
      // The following permissions are required for simple upload, form upload and fragment upload. Please see the list of other permissions https://cloud.tencent.com/document/product/436/31923
      config.put("allowActions", new String[] {
              "name/cos:PutObject",// Simple upload
              "name/cos:PostObject",// Form upload, applet upload
              "name/cos:GetBucket", // Allows you to get a list of objects for the bucket
              // Fragment upload
              "name/cos:InitiateMultipartUpload",
              "name/cos:ListMultipartUploads",
              "name/cos:ListParts",
              "name/cos:UploadPart",
              "name/cos:CompleteMultipartUpload"
      });

      //The temporary key information is returned successfully, and the key information is printed as follows
      credential = CosStsClient.getCredential(config);
    } catch (Exception e) {
      //Failure throw exception
      e.printStackTrace();
      throw new IllegalArgumentException("no valid secret !");
    }
    return Result.success(credential);

allowPrefixes corresponds to the resource of the policy (originally allowPrefix, which can be obtained from the source code)

allowActions corresponds to the action of the policy

policy learn more: https://cloud.tencent.com/document/product/436/31923

2. finish writing sth. java It's time to write the front-end applet in the background

cos.ts

// cos.ts
const COS = require('cos-wx-sdk-v5');


var cos = new COS({
  getAuthorization: function (options: any, callback: any) {
    console.log(options);
    
    wx.request({
      url: 'http://127.0.0.1:8080/qc/key',
      data: {
      },
      dataType: 'json',
      success: function (result: any) {
        var data = result.data.data;
        console.log(data);
        var credentials = data && data.credentials;
        if (!data || !credentials) return console.error('credentials invalid');
        callback({
          TmpSecretId: credentials.tmpSecretId,
          TmpSecretKey: credentials.tmpSecretKey,
          XCosSecurityToken: credentials.sessionToken,
          // It is recommended to return the server time as the signature start time to avoid signature errors caused by excessive local time deviation of the user browser
          StartTime: data.startTime, // Timestamp, in seconds, for example: 1580000000
          ExpiredTime: data.expiredTime, // Timestamp, in seconds, e.g. 1580000900
        });
      }
    });
  }
});

export {
  cos
}

app.ts: app file

import { cos } from './COS/cos';

App<IAppOption>({
  globalData: {
  },
  onLaunch() {
    cos.getBucket({
      Bucket: 'myblogspringboot-1300326898',
      Region: 'ap-nanjing',
      Prefix: 'avatar/', // Here, pass in all the files listed under myblogspringboot-1300326898/avatar
    }, function (err: any, data: any) {
      if (err) {
        console.log(err);
        return;
      }
      console.log(data, 2);
    });
  },
})
  • Request result

Official method 2 (not recommended online, recommended test): pure front end, simple

cos.ts

// cos.ts
const COS = require('cos-wx-sdk-v5');

var cos = new COS({
  SecretId: 'AKIDxxxxxxxxxxxxxxxxxxxxxx', // This is permanent
  SecretKey: '0mJbdT6UdWBbmjRu75pKbeT4QXP1PYS7' // Permanent
});

export {
  cos
}

Permanent secret key acquisition method: https://console.cloud.tencent.com/cam/capi

app.ts: it's the same

import { cos } from './COS/cos';

App<IAppOption>({
  globalData: {
  },
  onLaunch() {
    cos.getBucket({
      Bucket: 'myblogspringboot-1300326898',
      Region: 'ap-nanjing',
      Prefix: 'avatar/', // Here, pass in all the files listed under myblogspringboot-1300326898/avatar
    }, function (err: any, data: any) {
      if (err) {
        console.log(err);
        return;
      }
      console.log(data, 2);
    });
  },
})
  • result

Putting this important secret key on the front end is definitely not safe, so the official recommends method 1

Simple use and encapsulation of applet SDK

utils.ts: own tool class

/**
 * utils Common tools
 */
class Utils {

  /**
   * Get UUID
   * @returns 
   */
  static uuid() {
    return 'xxxxxxxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
      var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
    });
  }

  /**
   * Date formatting
   * @param fmt 
   * @param date 
   * @returns 
   */
    static dateFormat(fmt: string, date: Date) {
      date instanceof Date ? '' : date = new Date(date);
  
      let ret;
      const opt: any = {
        "Y+": date.getFullYear().toString(),        // year
        "m+": (date.getMonth() + 1).toString(),     // month
        "d+": date.getDate().toString(),            // day
        "H+": date.getHours().toString(),           // Time
        "M+": date.getMinutes().toString(),         // branch
        "S+": date.getSeconds().toString()          // second
        // There are other formatting character requirements that can continue to be added and must be converted into a string
      };
      for (let k in opt) {
        ret = new RegExp("(" + k + ")").exec(fmt);
        if (ret) {
          fmt = fmt.replace(ret[1], (ret[1].length == 1)
            ?
            (opt[k])
            :
            (opt[k].padStart(ret[1].length, "0")));
        };
      };
      return fmt;
    }

    /**
     * File name get random file name abc.jpg = > ABC_ 89dac3004cbdee7f7.jpg
     * @param filename 
     * @returns 
     */
    static randomFileName(filename: String): string {
      const separator: string = '.';
      const fileNameArr: Array<string> = filename.split(separator);
      return fileNameArr[0] + '_' + this.uuid() + '.' + fileNameArr[1];
    }
}

export {
  Utils
}

cos.ts: encapsulation of cos

// cos.ts
const COS = require('cos-wx-sdk-v5');
import { Utils } from '../utils/util';
import { UploadFilesArgOP } from '../interface/index';

class MyCOS {
  public AVATAR_PREFIEX: string = 'avatar/'; // Default storage path (avatar)
  public BASE_COS_JAVA_KEY_SERVER: string = 'http://127.0.0.1:8080/qc/key'; // java services
  public BUCKET: string = 'myblogspringboot-1300326898';
  public REGION: string = 'ap-nanjing'; // region
  public cos: any;

  /**
 * Get all files under avatar / *
 * @returns promise
 */
  public getBucket(): any {
    return new Promise((resolve: any): void => {
      this.cos.getBucket({
        Bucket: this.BUCKET,
        Region: this.REGION,
        Prefix: 'avatar/', // Here, pass in all the files listed under myblogspringboot-1300326898/avatar
      }, function (err: any, data: any) {
        err ? resolve(err) : '';
        resolve(data.Contents);
      });
    })
  }

  /**
   * Simple upload file
   * @param f 
   * @param progress 
   * @returns 
   */
  public simpleUpload(f: WechatMiniprogram.ChooseFile, progress: Function): any{
    return new Promise((resolve: (value: unknown) => void) => {
      this.cos.postObject({
        Bucket: this.BUCKET,
        Region: this.REGION,
        Key: this.AVATAR_PREFIEX + Utils.randomFileName(f.name),
        FilePath: f.path, 
        onProgress: function (progressData: any) {
          progress(progressData);
        }
      }, function (err: any, data: any) {
        resolve(err || data);
      });
    });
  }

  /**
* Upload a single file
* @param key File upload path
* @param path Local file path
* @param taskReady Ready to upload callback
* @param progress  Upload progress callback
* @param fileFinish Upload completion callback
* @returns 
*/
  uploadFile(key: string, path: string, taskReady?: Function, progress?: Function, fileFinish?: Function): object {
    return new Promise(resolve => {
      this.cos.uploadFile({
        Bucket: this.BUCKET, /* must */
        Region: this.REGION,     /* Bucket region, required */
        Key: key,              /* must */
        FilePath: path,                /* must */
        SliceSize: 1024 * 1024 * 20,     /* Trigger the threshold of block upload. If it exceeds 5MB, block upload is used. It is not necessary */

        // It is not required. The callback function when the upload task is created

        onTaskReady: function (taskId: number) {
          taskReady ? taskReady(taskId) : '';
        },

        // The progress callback function for uploading files is not required
        onProgress: function ({ loaded, total, speed }: { loaded: number, total: number, speed: number }) {
          progress ? progress(loaded, total, speed) : '';
        },

        // File upload completion callback, not required
        onFileFinish: function (err: any, data: any, options: any) {
          fileFinish ? fileFinish(err, data, options) : '';
        },

      }, function (err: any, data: any) {
        err ? resolve(err) : resolve(data);
      });
    });
  }


  /**
   * Upload multiple files
   * @param files 
   * @param taskReady 
   * @param progress 
   * @param fileFinish 
   * @returns 
   */
  uploadMoreFile(files: WechatMiniprogram.ChooseFile[], taskReady?: Function, progress?: Function, fileFinish?: Function) {

    // Iterative shallow copy
    const uploadFiles: UploadFilesArgOP[] = files.
      map((item: WechatMiniprogram.ChooseFile) => {
        return Object.assign(item, {
          FilePath: item.path,
          FileSize: item.size,
          Bucket: this.BUCKET,
          Region: this.REGION,
          Key: this.AVATAR_PREFIEX + Utils.randomFileName(item.name),
          onTaskReady(taskId: number) {
            taskReady ? taskReady(taskId) : '';
          }
        })
      });

    return new Promise((resolve: (value: unknown) => void) => {
      this.cos.uploadFiles({
        files: uploadFiles,
        SliceSize: 1024 * 1024 * 10,    /* If the setting is greater than 10MB, block upload is adopted */

        // Progress callback
        onProgress: (info: any) => {
          console.log(info);
          progress ? progress(info.total, info.speed, info.percent) : '';
        },

        // Complete all or error callback
        onFileFinish: (err: any, data: any, options: any) => {
          fileFinish ? fileFinish(err || data, options) : '';
        },
      }, function (err: any, data: any) {
        resolve(err || data);
      });
    })
  }

  /**
   * All COS tasks
   */
  allTasks(): Array<any> {
    return this.cos.getTaskList();
  }

  /**
   * Clear specified task
   * @param taskId 
   * @returns 
   */
  clearTask(taskId: string) {
    return this.cos.cancelTask(taskId);
  }

  /**
   * Pause the specified task
   * @param taskId 
   */
  pauseTask(taskId: string) {
    this.cos.pauseTask(taskId);
  }


  /**
   * Restart the specified task
   * @param taskId 
   */
  reStartTask(taskId: string) {
    this.cos.restartTask(taskId);
  }
}
const myCos: MyCOS = new MyCOS();
myCos.cos = new COS({
  getAuthorization: function (options: any, callback: any) {
    // console.log('options', options);

    wx.request({
      url: myCos.BASE_COS_JAVA_KEY_SERVER,
      data: {},
      dataType: 'json',
      success: function (result: any) {
        var data = result.data.data;
        var credentials = data && data.credentials;
        if (!data || !credentials) return console.error('Invalid voucher...');
        callback({
          TmpSecretId: credentials.tmpSecretId,
          TmpSecretKey: credentials.tmpSecretKey,
          XCosSecurityToken: credentials.sessionToken,
          // It is recommended to return the server time as the signature start time to avoid signature errors caused by excessive local time deviation of the user browser
          StartTime: data.startTime, // Timestamp, in seconds, for example: 1580000000
          ExpiredTime: data.expiredTime, // Timestamp, in seconds, e.g. 1580000900
        });
      }
    });
  }
})
export default myCos;

  • Source code

Code cloud address: https://gitee.com/JYbill/cos_wx_sdk-demo

Github address: https://github.com/JYbill/cos_wx_sdk-demo

  • test

  • There is a BUG that uses Wx SDK through the official document

    cos.pauseTask, cos.restartask and cos.cancelTask operate tasks. On the surface, the front end suspends or cancels the task (I checked that the id passed is correct) or continues to upload.

Scenario: upload 3M pictures, click Cancel and pause, and after a few seconds, Tencent cloud object storage COS console still has successfully uploaded pictures. There is no reason why the transmission speed is too fast, and the same is true for 5M pictures.

Tags: Java SDK Mini Program

Posted on Wed, 22 Sep 2021 23:39:03 -0400 by fractalvibes