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

推荐订阅源

Apple Machine Learning Research
Apple Machine Learning Research
AWS News Blog
AWS News Blog
Google DeepMind News
Google DeepMind News
U
Unit 42
博客园 - 叶小钗
博客园 - 聂微东
GbyAI
GbyAI
Stack Overflow Blog
Stack Overflow Blog
有赞技术团队
有赞技术团队
aimingoo的专栏
aimingoo的专栏
D
DataBreaches.Net
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Jina AI
Jina AI
美团技术团队
The Cloudflare Blog
M
MIT News - Artificial intelligence
Microsoft Azure Blog
Microsoft Azure Blog
I
InfoQ
S
Schneier on Security
C
Check Point Blog
Project Zero
Project Zero
The Hacker News
The Hacker News
Scott Helme
Scott Helme
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Cisco Talos Blog
Cisco Talos Blog
P
Privacy International News Feed
SecWiki News
SecWiki News
Latest news
Latest news
MongoDB | Blog
MongoDB | Blog
S
Secure Thoughts
Google Online Security Blog
Google Online Security Blog
F
Fortinet All Blogs
博客园 - 三生石上(FineUI控件)
H
Help Net Security
TaoSecurity Blog
TaoSecurity Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Last Week in AI
Last Week in AI
P
Privacy & Cybersecurity Law Blog
Forbes - Security
Forbes - Security
G
GRAHAM CLULEY
N
Netflix TechBlog - Medium
L
Lohrmann on Cybersecurity
A
About on SuperTechFans
T
The Exploit Database - CXSecurity.com
C
Cisco Blogs
PCI Perspectives
PCI Perspectives
大猫的无限游戏
大猫的无限游戏
T
Troy Hunt's Blog
H
Hacker News: Front Page
Vercel News
Vercel News

博客园 - 青玄鸟

.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')!