惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
B
Blog RSS Feed
宝玉的分享
宝玉的分享
腾讯CDC
博客园_首页
T
Tailwind CSS Blog
月光博客
月光博客
博客园 - 司徒正美
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
M
MIT News - Artificial intelligence
A
About on SuperTechFans
云风的 BLOG
云风的 BLOG
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
有赞技术团队
有赞技术团队
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
大猫的无限游戏
大猫的无限游戏
MongoDB | Blog
MongoDB | Blog
博客园 - 聂微东
V
Visual Studio Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
SecWiki News
SecWiki News
美团技术团队
P
Privacy International News Feed
H
Help Net Security
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
Microsoft Security Blog
Microsoft Security Blog
Know Your Adversary
Know Your Adversary
Y
Y Combinator Blog
D
DataBreaches.Net
Project Zero
Project Zero
T
The Blog of Author Tim Ferriss
Cyberwarzone
Cyberwarzone
C
Cybersecurity and Infrastructure Security Agency CISA
C
Cisco Blogs
S
Schneier on Security
G
GRAHAM CLULEY
博客园 - 三生石上(FineUI控件)
Cisco Talos Blog
Cisco Talos Blog
小众软件
小众软件
Forbes - Security
Forbes - Security
D
Docker
T
Tenable Blog
S
Secure Thoughts
雷峰网
雷峰网
S
Security @ Cisco Blogs
T
The Exploit Database - CXSecurity.com
The Cloudflare Blog
博客园 - 【当耐特】
Spread Privacy
Spread Privacy
阮一峰的网络日志
阮一峰的网络日志

博客园 - 青玄鸟

.NET 中优雅处理 Server-Sent Events 请求取消 Dapr 订阅者参数无法正确反序列化问题 .NET 代码整洁手册 Blazor项目通过docker和nginx部署为静态站点的步骤 Moq mock 方法返回null空指针异常 基于接口隔离原则的依赖注入实现 HttpClient with Stream HttpClient partial update HttpClient 基本使用 值对象的封装 只读集合类型属性实现 适配器模式 模板模式 最少知识原则 单例模式 抽象工厂 简单工厂、工厂方法、抽象工厂 工厂方法模式 使用 Visual Studio Code创建和执行T-SQL
vue3.0 + ts 实现上传工厂(oss与cos)
青玄鸟 · 2023-11-06 · via 博客园 - 青玄鸟

概述

将上传基类命名为MOS(Mine Object Storage)

mos.ts代码

import {MosType} from './mosConfig'
import {Loading} from '../loading'
import {type BinaryFile, type MosFile} from './fileUtil'
import type { PathTemplate } from './pathTemplate'
import axios, { type AxiosResponse } from 'axios'
import {loadUser} from '../user'
export interface MosSettings{
    cdn:string | null
    bucket:string
    endpoint:string
}

export interface UploadOptions{
    cover:boolean 
    progress?:Function
    failed?:Function
}

export abstract class Mos{
    settings : MosSettings
    finished : boolean = false
    loading : Loading
    pathTemplate:string 

    constructor(settings:MosSettings,template:PathTemplate){
        this.settings = settings
        this.loading = new Loading()
        this.pathTemplate = `${template.appId}/@ownerId/@fileName`
    }

    abstract init() : void

    abstract uploadFile(file:BinaryFile,options:UploadOptions,token:string) : Promise<MosFile|null>

    async upload(file:BinaryFile,options:UploadOptions) : Promise<MosFile|null> {
        const user=loadUser()
        this.pathTemplate=this.pathTemplate.replace('@ownerId',user?.userId.toString() ?? '0')
        return await this.uploadFile(file,options,user?.token ?? '')
    }

    async getCredential(token:string,bucket:string,type: MosType) : Promise<AxiosResponse<any, any>>{
        const params = { bucket: bucket, ossSource: type }
        const url = `https://api.mos.com/api/v1/Credential` // 接口会根据不同的ossSource参数值返回不同的数据结构,因此可以放在基类

        return axios.get(url, { params ,headers:{
            'Authorization':token,
            'Content-Type':'application/json'
        }})
    }
}

oss.ts代码

import axios from "axios";
import type { BinaryFile, MosFile } from "./fileUtil";
import { Mos, type UploadOptions } from "./mos";
import { MosType, type OssConfig } from "./mosConfig";
import type { OssCredential } from "./mosCredential";
import type { PathTemplate } from "./pathTemplate";

export class Oss extends Mos{
    policy : string = ''
    signature : string = ''
    accessKeyId:string
    host:string

    constructor(config:OssConfig,template:PathTemplate) {
        super({bucket:config.bucket,endpoint:config.endpoint,cdn:config.cdn},template)
        this.accessKeyId = config.accessKeyId
        this.host=`https://${config.bucket}.${config.endpoint}`
    }

    init() {
        return
    }

    async getSTSToken(token:string){
        if (this.policy) return Promise.resolve()
        
        return await this.getCredential(token,this.settings.bucket,MosType.Oss).then(result => {
            const data = result.data.data as OssCredential;
            this.policy = data.policy;
            this.signature = data.signature;
        })
    }

    async uploadFile(file: BinaryFile, options: UploadOptions,token:string): Promise<MosFile|null> {
        this.finished = false
        this.loading.startLoading()
        await this.getSTSToken(token)
        const fileName = file.name
        const ossPrefix = 'TempFiles/'
        const saveKey = ossPrefix + this.pathTemplate.replace('@fileName',fileName)

        const formData = new FormData();
        formData.append("policy", this.policy);
        formData.append("Signature", this.signature);
        formData.append("bucket", this.settings.bucket);
        formData.append("key", saveKey);
        formData.append("OSSAccessKeyId", this.accessKeyId);
        formData.append("success_action_status", "201");

        formData.append("Content-Disposition", "attachment;filename=" + fileName + ";filename*=UTF-8''" + fileName);
        formData.append("file", file.binary);

        return axios.post(this.host, formData, {
            responseType: 'document',
            onUploadProgress: evt => options.progress && options.progress(evt),
        }).then(result => {
            this.finished = true;
            this.loading.endLoading();

            console.log("上传成功");

            const data = result.data;
            const url = data.getElementsByTagName("Location")[0].childNodes[0].nodeValue;

            return url ? Promise.resolve({ url,  fileName }) : Promise.reject(result);
        }).catch(error => {
            this.finished = true;
            this.loading.endLoading()

            console.log("上传失败");

            options.failed &&options.failed(error);

            return null
        })
    }    

}

cos.ts 代码

import type { BinaryFile, MosFile } from './fileUtil'
import { Mos, type UploadOptions } from './mos'
import { MosType, type CosConfig } from './mosConfig'
import type { PathTemplate } from './pathTemplate'
import COS from 'cos-js-sdk-v5'
import type { CosCredential } from './mosCredential'

export class TencentCOS extends Mos {
  cos: COS | null = null
  currentToken:string = ''

  constructor(config: CosConfig, template: PathTemplate) {
    super({ bucket: config.bucket, endpoint: config.endpoint, cdn: config.cdn }, template)
  }

  init() {
    this.cos = new COS({
      getAuthorization:  (options, callback) => this.getAuthorizationCredential(callback),
      UploadCheckContentMd5: true 
    })
  }
  async uploadFile(file: BinaryFile, options: UploadOptions, token: string): Promise<MosFile | null> {
    this.currentToken = token
    this.finished = false;
    this.loading.startLoading()
    const fileName = file.name
    const savekey = this.pathTemplate.replace('@fileName',fileName)
    return new Promise((resolve, reject) => {
        this.cos!.uploadFile({
            Bucket: this.settings.bucket,
            Region: this.settings.endpoint,
            Key: savekey,
            Body: file.binary,
            SliceSize: 1024 * 1024 * 5, 
            Headers: {
                'content-disposition': "attachment;filename=" + fileName + ";filename*=UTF-8''" + fileName
            },
            onProgress: evt => options.progress && options.progress(evt),
        }, (err, data) => {
            this.finished = true;
            this.loading.endLoading()

            if (err) {
                console.log("上传失败");
                options.failed && options.failed(err);
                reject(err);
            }
            if (data) {
                console.log("上传成功");
                resolve({ url, fileName });
            }
        });
    })
  }

  getAuthorizationCredential(callback:Function){
      this.getCredential(this.currentToken, this.settings.bucket, MosType.Cos).then((result) => {
      const data = result.data.data as CosCredential
      callback({
        TmpSecretId: data.tmpSecretId,
          TmpSecretKey: data.tmpSecretKey,
          SecurityToken: data.token,
          StartTime: data.startTime,
          ExpiredTime: data.expiredTime
      })
    })
  }

}

mosFactory.ts 代码

import { TencentCOS as Cos } from "./cos";
import type { Mos } from "./mos";
import {MosConfig, MosType } from "./mosConfig";
import { Oss } from "./oss";
import type { PathTemplate } from "./pathTemplate";

export function CreateMos (template:PathTemplate,type:MosType = MosType.Cos) : Mos {
    const config:MosConfig = new MosConfig()
    let mos:Mos 
    switch (type) {
        case MosType.Cos:
            mos= new Cos(config.cos,template)
            break;
        case MosType.Oss:
            mos= new Oss(config.oss,template)
            break
        default:
            mos= new Cos(config.cos,template)
            break;
    }
    mos.init()

    return mos
}

export function CreateDefaultMos(type:MosType = MosType.Cos) : Mos {
    return CreateMos({appId:'demo'},type)
}

其他代码

PathTemplate.ts

export interface PathTemplate{
    appId:string //应用Id 
}

mossCredential.ts

export interface OssCredential{
    policy:string
    signature:string
    accessKeyId:string|null
}

export interface CosCredential{
    tmpSecretId:string
    tmpSecretKey:string
    token:string
    startTime:number
    expiredTime:number
}

fileUtil.ts

export interface MosFile {
  url: string | null
  fileName: string
}

export interface BinaryFile{
  binary: Blob
  name:string
}

mosConfig.ts

export interface OssConfig {
  isTemp: boolean
  bucket: string
  endpoint: string
  cdn: string
  accessKeyId: string
}
export interface CosConfig{
    bucket: string
    endpoint: string
    cdn: string
}

export class MosConfig {
  oss: OssConfig = {
    bucket: 'demo-bucket',
    endpoint: 'oss-cn.aliyuncs.com',
    cdn: '',
    accessKeyId: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
  }
  cos:CosConfig = {
    bucket: 'demo-bucket',
    endpoint: 'beijing',
    cdn: ""
  }
}

export enum MosType{
    Oss = 1,
    Cos
}

在vue3.0是使用

在App.vue中

import {provide} from 'vue'
import {CreateDefaultMos} from './assets/ts/mos/mosFactory'

provide('mos',CreateDefaultMos())

在组件中注入使用

import {inject } from 'vue'

const mos:Mos = inject('mos')!