您现在的位置是:首页 > 正文

上传文件到阿里oss

2024-02-01 00:49:14阅读 2

上传文件到阿里oss

代码示例
阿里云官方文档

项目中一般会遇到上传图片或者文件到oss上,本次采用阿里云的oss,上传方式有两种:一种是先上传到服务器再上传到oss然后删除服务器上的文件,第二种直接上传到oss上

使用了下面两个API

client.put

client.put(name, file[, options]),put接口将(本地路径、Buffer、ReadStream)、(File、Blob只支持在浏览器端)上传到OSS

  • git文档
  • name : 上传到oss的路径名称
  • file: {String|Buffer|ReadStream|File(only support Browser)|Blob(only support Browser)} object local path, content buffer or ReadStream content instance use in Node, Blob and html5 File

流式上传:client…putStream

client…putStream(name, stream[, options]),添加一个流文件到oss上

  • git文档

  • name : 上传到oss的路径名称

  • stream: {ReadStream} object ReadStream content instance

第一种方案

前端先将文件上传给后端,后端先将文件存储到服务器上,然后再将服务器中的文件上传到oss上,然后删除刚才的文件。这种方法只适用于较小的文件,因为大文件会占用服务器内存。不推荐

这里的案例直接用之前大文件切片上传的代码,具体参考:大文件切片上传
主要就是在merge方法里调用:

node端:

module.exports = (app) => {
    const express = require('express');
    const router = express.Router();
    const multiparty = require('multiparty')
    const fs = require('fs')
    const fse = require('fs-extra')
    const path = require('path')
    const OSS = require('ali-oss');

    const upload_dir = __dirname + '/../../uploadsMultipart/slice'


    const headers = {
        // 指定Object的存储类型。
        'x-oss-storage-class': 'Standard',
        // 指定Object的访问权限。
        'x-oss-object-acl': 'private',
        // 设置Object的标签,可同时设置多个标签。
        'x-oss-tagging': 'Tag1=1&Tag2=2',
        // 指定PutObject操作时是否覆盖同名目标Object。此处设置为true,表示禁止覆盖同名Object。
        'x-oss-forbid-overwrite': 'true',
    };
    const client = new OSS({
        // yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
        region: 'yourregion',
        // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
        accessKeyId: 'yourAccessKeyId',
        accessKeySecret: 'yourAccessKeySecret',
        // 填写Bucket名称。
        bucket: 'examplebucket'
    })
    router.post('/uploadSlice', (req, res) => {
        const form = new multiparty.Form({ uploadDir: upload_dir })
        form.parse(req)
        form.on('file', async (name, chunk) => {
            console.log(chunk);
            // 存放切片的目录 
            let chunkDir = `${upload_dir}/${chunk.originalFilename.split('.')[0]}`
            if (!fse.existsSync(chunkDir)) {
                await fse.mkdirs(chunkDir)
            }
            // 原文件名
            let dPath = path.join(chunkDir, chunk.originalFilename.split('.')[1])
            // 移动文件
            await fse.move(chunk.path, dPath, { overwrite: true })
            res.send('文件上传成功')
        })
    })
    router.post('/merge', async (req, res) => {
        let name = req.body.name
        let fname = name.split('.')[0]
        let chunkDir = path.join(upload_dir, fname)
        let chunks = await fse.readdir(chunkDir)
        chunks.sort((a, b) => a - b).map(chunkPath => {
            fs.appendFileSync(
                path.join(upload_dir, name),
                fs.readFileSync(`${chunkDir}/${chunkPath}`)
            )
        })
        fse.removeSync(chunkDir)
        const pathFile = upload_dir + '/' + name
        const result = await client.put(name, path.normalize(pathFile) // 此处上传到oss-----------------
            // 自定义headers
            , { headers }
        );
        console.log('result', result);
        res.send({
            msg: '合并成功',
            url: `http://localhost:9000/uploadsMultipart/slice/${name}`
        })
    })
    app.use('/admin/api', router);
}

第二种方案

前端将文件传给后端,后端直接将流或者buffer推送到oss上。推荐,不会占用服务端的内存

使用流式上传上传需要注意,要先把前端传来的buffer格式转为stream流格式

let Duplex = require('stream').Duplex;
    function bufferToStream(buffer) {
        let stream = new Duplex();
        stream.push(buffer);
        stream.push(null);
        return stream;
    }
module.exports = (app) => {
    const express = require('express');
    const fs = require('fs');
    const router = express.Router();
    const OSS = require('ali-oss');
    const multer = require('multer')
    
    // 将buffer转为stream流
    let Duplex = require('stream').Duplex;
    function bufferToStream(buffer) {
        let stream = new Duplex();
        stream.push(buffer);
        stream.push(null);
        return stream;
    }
    const headers = {
        // 指定Object的存储类型。
        'x-oss-storage-class': 'Standard',
        // 指定Object的访问权限。
        'x-oss-object-acl': 'private',
        // 设置Object的标签,可同时设置多个标签。
        'x-oss-tagging': 'Tag1=1&Tag2=2',
        // 指定PutObject操作时是否覆盖同名目标Object。此处设置为true,表示禁止覆盖同名Object。
        'x-oss-forbid-overwrite': 'true',
    };
    const client = new OSS({
        // yourRegion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
        region: 'yourregion',
        // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
        accessKeyId: 'yourAccessKeyId',
        accessKeySecret: 'yourAccessKeySecret',
        // 填写Bucket名称。
        bucket: 'examplebucket'
    })
    // 不保存在本地
    const storage = multer.memoryStorage()
    const upload = multer({ storage }) // 这段代码设置文件不在本地保存
    const month = new Date().getMonth() + 1
    // 以年月日作为上传文件夹的名称
    let ossPath = new Date().getFullYear() + '-' + month + '-' + new Date().getDate()
    router.post('/uploadOss', upload.single('file'), async (req, res) => {
        // 使用put方法上传buffer
        let result = await client.put('ossdemo/' + ossPath + '/' + req.file.originalname, req.file.buffer);
        //使用putStream上传流到oss
        // let result = await client.putStream('ossdemo/' + req.file.originalname, bufferToStream(req.file.buffer));
        console.log(result);
        res.send({
            code: 200,
            msg: '上传成功',
            data: {
                url: result.url
            }
        })
    })
    app.use('/admin/api', router);
}

网站文章

  • MySQL优化

    MySQL优化

    这里特别强调一下分片规则的选择问题,如果某个表的数据有明显的时间特征,比如订单、交易记录等,则他们通常比较合适用时间范围分片,因为具有时效性的数据,我们往往关注其近期的数据,查询条件中往往带有时间字段...

    2024-02-01 00:48:55
  • 继承(Java)

    继承(Java)

    继承定义继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模比如说Person是父类,YellowPerson,WhitePerson,BlackPerson就是子类extends的意思是”扩展...

    2024-02-01 00:48:39
  • DES

    http://www.hankcs.com/security/des-algorithm-illustrated.html

    2024-02-01 00:48:11
  • AsyncLoadScene场景的异步加载---Loading界面

    在游戏开发过程中,常常需要Loading界面。一方面是为了等待后台加载场景;一方面也是为了美观,可以在Loading界面放上游戏里有趣的截图,战斗场面,小提示等。自己最近做的毕业设计中使用了场景的异步加载来使游戏变得更加完整和有趣,这些api用的比较少,所以代码贴上来记录一下。 /* * 所属层级:工具层 * 脚本功能:异步加载场景 * * */ using Uni...

    2024-02-01 00:48:01
  • 江苏大专英语计算机考试,南京农业大学2019年上半年江苏省专科计算机英语统考时间的通知...

    江苏大专英语计算机考试,南京农业大学2019年上半年江苏省专科计算机英语统考时间的通知...

    2019年上半年全省成人高等教育英语、计算机基础课程统考定于6月22日、23日进行。现将有关事宜通知如下:一、考试内容英语课程统考考试大纲不变,与去年考核范围一致。1、计算机基础课程统考中无Micro...

    2024-02-01 00:47:55
  • 数值计算与计算机应用杂志,数值计算与计算机应用杂志

    《数值计算与计算机应用》是由中国科学院数学与系统科学研究院主办的学术性刊物, 季刊,国内外公开发行.《数值计算与计算机应用》主要报道: 应用计算机解决各种科学和工程问题的数学模型、计算方法、软件技术和...

    2024-02-01 00:47:50
  • 在一行中按照格式“yyyy/mm/dd”(即“年/月/日”)给出日期,计算某年某月某日是该年中的第几天。 热门推荐

    #include using namespace std; int main(int argc, char *argv[]) { char a[11]; cin.getline(a, 11); int sum = 10 * (a[8] - '0') + a[9] - '0'; int b[13] = { 0,31,28,31,30,31,30,31...

    2024-02-01 00:47:11
  • metasploit 简介

    0x00:简介metasploit 是一个开源框架,这个框架用来做渗透测试,其 msf 是由多个不同的模块组成的,在使用方面的话,可以在 kali 中直接使用,命令行 msfconsole 即可。metasploit 会经常更新其中的一些模块和内容,若在 kali 中使用,建议经常更新,命令一般是 apt-get update,apt-get upgrade,apt-get dist-up...

    2024-02-01 00:46:59
  • Contest 2050 and Codeforces Round #718 B. Morning Jogging

    题目连接:https://codeforces.com/contest/1517/problem/B The 2050 volunteers are organizing the “Run! Chas...

    2024-02-01 00:46:32
  • synchronized

    1、synchronized关键字的作用域有二种: 1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有...

    2024-02-01 00:46:23