vue3+typescript upload files to qiniu cloud

Posted by samip1983 on Mon, 07 Mar 2022 20:07:06 +0100

Personal blog address of this article: https://www.leafage.top/posts/detail/21414BX0U

The leafage MS project has been written for a long time, but it has not completed the function of uploading files. I read the documents of qiniu cloud several times before, tossed for several times, and failed. Today, I made up my mind to solve this problem, so I began to look for materials, documents and examples, and finally got it.

Vite is used in the project JS is built and typescript is used. There are few online examples. Let's record how to implement it step by step. The example code of qiniu cloud can't be accessed directly. There's no address here. Just look at the process.

First, install qiniu JS and crypto JS dependencies. Qiniu JS is upload. Crypto JS (added. d.ts support) is a tool for encryption when generating token. The installation command is as follows:

yarn add crypto-js qiniu-js -D

Create a new upload in the tools / plug-ins directory TS file, referring to the official documents to write the upload method, encryption and token generation methods, the first is the upload method, and the final code is as follows:

import * as qiniu from 'qiniu-js';
import CryptoJS from 'crypto-js'

// Request interface to upload pictures
export function uploadFile(file: File) {
    const uptoken = getToken("ss", "xx", "xx");
    const key = file.name;
    const config = {
        useCdnDomain: true,
        region: qiniu.region.z2,
        forceDirect: true // Whether direct transmission is adopted for all uploads
    };
    const putExtra: any = {
        fname: file.name, //File original file name
        mimeType: ['image/png', 'image/jpeg', 'image/gif'] //It is used to limit the type of uploaded file. When null, it means that there is no restriction on the file type;
    };
    return qiniu.upload(file, key, uptoken, putExtra, config);
}

Note that the final result returned here is the execution result of upload(), which is an object with next, error and complete. The process and result are not processed here. It is returned directly and processed where it is used.

The uploadFile() method needs to be exposed for use in the component

The three parameters of the getToken() method are accessKey, secretKey and bucketName. You need to log in to your qiniu cloud account to check. After logging in, click the avatar and then click key management. The final code of the getToken() method is as follows:

function getToken(access_key: string, secret_key: string, bucketname: string) {
    // Construction strategy
    var putPolicy = {
        "scope": bucketname,
        "deadline": 3600 + Math.floor(Date.now() / 1000)
    }
    var encoded = base64Encode(utf16to8(JSON.stringify(putPolicy)));
    var hash = CryptoJS.HmacSHA1(encoded, secret_key);
    // Construct voucher
    var encodedSign = hash.toString(CryptoJS.enc.Base64).replace(/\//g, '_').replace(/\+/g, '-');
    var uploadToken = access_key + ':' + encodedSign + ':' + encoded;
    return uploadToken;
}

The code implementation of base64Encode() and utf16to8() in getToken() method is as follows:

function base64Encode(str: string) {
    var out, i, len;
    var c1, c2, c3;
    len = str.length;
    i = 0;
    out = "";
    var base64EncodeChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
    while (i < len) {
        c1 = str.charCodeAt(i++) & 0xff;
        if (i == len) {
            out += base64EncodeChars.charAt(c1 >> 2);
            out += base64EncodeChars.charAt((c1 & 0x3) << 4);
            out += "==";
            break;
        }
        c2 = str.charCodeAt(i++);
        if (i == len) {
            out += base64EncodeChars.charAt(c1 >> 2);
            out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
            out += base64EncodeChars.charAt((c2 & 0xF) << 2);
            out += "=";
            break;
        }
        c3 = str.charCodeAt(i++);
        out += base64EncodeChars.charAt(c1 >> 2);
        out += base64EncodeChars.charAt(((c1 & 0x3) << 4) | ((c2 & 0xF0) >> 4));
        out += base64EncodeChars.charAt(((c2 & 0xF) << 2) | ((c3 & 0xC0) >> 6));
        out += base64EncodeChars.charAt(c3 & 0x3F);
    }
    return out;
}
function utf16to8(str: string) {
    var out, i, len, c;
    out = "";
    len = str.length;
    for (i = 0; i < len; i++) {
        c = str.charCodeAt(i);
        if ((c >= 0x0001) && (c <= 0x007F)) {
            out += str.charAt(i);
        } else if (c > 0x07FF) {
            out += String.fromCharCode(0xE0 | ((c >> 12) & 0x0F));
            out += String.fromCharCode(0x80 | ((c >> 6) & 0x3F));
            out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
        } else {
            out += String.fromCharCode(0xC0 | ((c >> 6) & 0x1F));
            out += String.fromCharCode(0x80 | ((c >> 0) & 0x3F));
        }
    }
    return out;
}

The whole upload method is completed and then used in the component. The example is as follows:

import { uploadFile } from "../../plugins/upload";

Add a control to html, for example:

<div class="mx-auto text-center">
    <div class="text-center text-gray-600">
          <label
              for="file-upload"
              class="relative cursor-pointer bg-white rounded-md text-gray-400 hover:text-indigo-500"
           >
                <svg
                   class="mx-auto h-8 w-8"
                   stroke="currentColor"
                   fill="none"
                   viewBox="0 0 48 48"
                   aria-hidden="true"
                >
                   <path
                      d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02"
                      stroke-width="2"
                      stroke-linecap="round"
                      stroke-linejoin="round"
                   />
                    </svg>
                    <input
                      id="file-upload"
                      name="cover"
                      type="file"
                      class="sr-only"
                      accept="image/png,image/jpeg,image/jpg"
                      @change="uploadImage($event.target.files)"
                    />
               </label>
          </div>
    <p class="text-xs text-gray-500">png, jpeg, jpg</p>
    <p class="text-xs text-gray-500">up to 2MB</p>
</div>

The uploadFile method is invoked in the method. The following example uploads only one file:

// Upload file
    uploadImage(files: Array<File>) {
      if (files.length > 0) {
        uploadFile(files[0]).subscribe({
          next: (result) => {
          },
          error: () => {
          },
          complete: (e) => {
            let data = {
              ...this.postsData,
              cover: "https://cdn.leafage.top/" + e.key,
            };
            this.postsData = data;
          },
        });
      }
    },

It's not easy to succeed here.

Topics: Javascript