Node.js零基础到项目实战 阿里云OSS

67 阅读1分钟

一、使用 http-errors 处理状态码

npm i http-errors

const createError = require('http-errors')

function failure(res, error) {
    let statusCode = 500
    let errors = '服务器错误'

    if(error.name === 'SequelizeValidationError') { // Sequelize 验证错误
        statusCode = 400
        errors = error.errors.map(err => err.message)
    } else if(error.name === 'JsonWebTokenError' || error.name === 'TokenExpiredError') { // Token验证错误
        statusCode = 401
        errors = 'Token验证失败'
    } else if(error instanceof createError.HttpError) { // http-errors 库创建的错误
        statusCode = error.status
        errors = error.message
    }

    res.status(statusCode).json({
        status:false,
        message: `请求失败:${error.name}`,
        errors: Array.isArray(errors) ? errors : [errors]
    })
}

二、使用Multer上传图片到阿里云 OSS(对象存储)

# 对象存储OSS -> Bucket列表 -> 创建Bucket
# Bucket名称:
# 地域:
# 阻止公共访问:关闭
# 读写权限:公众读
# 完成创建

# 直接使用阿里云网站上传
## 进入Bucket -> 上传文件 -> 选择文件 -> 点击上传

# 开发上传接口
# 服务端代理上传
## 客户端 - 上传文件 -> 业务服务器 - 上传文件 -> 对象存储
## 缺点:一张图片先上传到Node服务器上,再上传到阿里云OSS。这张图片上传两次,造成资源的浪费
## 优点:前端开发简单,后端也可以很方便的记录

# 客户端直传
## 客户端 - 获取授权 -> 业务服务器
## 客户端 - 上传文件 -> 对象存储
## 优点:图片不用经过客户端的中转,服务器开销非常小,上传速度也会快很多
## 缺点:开发上代码麻烦点,使用上前端需要调用两次接口

# 点击阿里云头像 -> AccessKey管理 -> 开始使用子用户AccessKey -> 创建用户
# OpenAPI调用访问 勾选 -> 确定 -> 手机号验证
# 选择用户 -> 添加权限 -> AliyunOSSFullAccess -> 确认新增授权
# 用户信息: AccessKey ID 和 AccessKey Secret

# node项目 .env文件增加配置
ALIYUN_ACCESS_KEY_ID= # AccessKey ID
ALIYUN_ACCESS_KEY_SECRET= # AccessKey Secret
ALIYUN_BUCKET= # 阿里云OSS -> 概览 -> 基本信息 -> 存储空间名称
ALIYUN_REGION= #阿里云OSS -> 概览 -> 访问端口 -> 地域节点 -> 小数点前面的部分

# 安装上传需要的依赖包
npm i ali-oss multer multer-aliyun-oss
# ali-oss 是用来操作阿里云OSS的SDK
# multer 上传文件的node.js中间件
# multer-aliyun-oss 是配置multer将文件上传到阿里云OSS

# 阿里云OSS -> 跨域设置 -> 创建规则
# 来源:*
# 允许Methods:POST
# 允许Headers:*
# 确认
const multer = require('multer')
const multerAliyunOss = require('multer-aliyun-oss')
const OSS = require('ali-oss')

// 阿里云配置信息
const config = {
    accessKeyId: process.env.ALIYUN_ACCESS_KEY_ID,
    accessKeySecret: process.env.ALIYUN_ACCESS_KEY_SECRET,
    bucket: process.env.ALIYUN_OSS_BUCKET,
    region: process.env.ALIYUN_OSS_REGION,
}

const client = new OSS(config)

// multer 配置信息
const upload = multer({
    storage: multerAliyunOss({
        config: config,
        destination: 'uploads', // 自定义上传目录
    }),
    limits: {
        fileSize: 1024 * 1024 * 5, // 限制文件大小为 5MB
    },
    fileFilter: (req, file, cb) => {
        // 限制文件类型为图片
        if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/)) {
            return cb(new Error('只支持上传图片文件'))
        }
        cb(null, true)
    },
})

// 单文件上传,指定表单字段名为 file
const singleUpload = upload.single('file')

module.exports = {
    config,
    client,
    singleUpload,
}

1. 服务端代理上传

const express = require('express')
const router = express.Router()
const { success, failure } = require('../utils/responses')

const { singleUpload } = require('../utils/aliyun')

/**
 * 阿里云 OSS 上传文件
 * @route POST /uploads/aliyun
 */
router.post('/aliyun', singleUpload, (req, res) => {
    try {
        singleUpload(req, res, (err) => {
            if (err) {
                return failure(res, err)
            }

            if(!req.file) {
                return failure(res, new Error('文件上传失败'))
            }

            success(res, '上传成功', {
                file: req.file
            })
        })
    } catch (error) {
        failure(res, error)
    }
})

module.exports = router

2、客户端直传

npm install uuid

const express = require('express')
const router = express.Router()
const { success } = require('../utils/responses')

const { client, config } = require('../utils/aliyun')
const {v4: uuidv4} = require('uuid')
const moment = require('moment')

/**
 * 获取直传阿里云 OSS授权信息
 * Get /uploads/aliyun/authorize
 */
router.get('/aliyun/authorize', async(req, res) => {
    // 有效期
    const date = moment().add(1, 'day')
    // 自定义上传目录和文件名
    const key = `uploads/${uuidv4()}`

    // 上传安全策略
    const policy = {
        expiration: date.toISOString(),
        conditions: [
            ['content-length-range', 0, 1024 * 1024 * 5], // 限制文件大小为 5MB
            {bucket: client.options.bucket}, // 限制上传的 bucket 
            ['eq', '$key', key], // 限制文件名
            ['eq', '$Content-Type', ['image/jpeg', 'image/png', 'image/gif', 'image/webp']], // 限制文件类型
        ],
    }

    // 签名
    const formData = await client.calculatePostSignature(policy)

    // bucket 域名 阿里云上传地址
    const host = `https://${config.bucket}.${await client.getBucketLocation().location}.aliyuncs.com`.toString()

    // 返回参数
    const params = {
        expires: date.format('YYYY-MM-DD HH:mm:ss'),
        policy: formData.policy,
        signature: formData.signature,
        accessid: formData.OSSAccessKeyId,
        host,
        key,
        url: `${host}/${key}`,
    }

    success(res, '获取阿里云授权信息', params)
})

module.exports = router

三、自动备份数据库到阿里云OSS

# 宝塔 -> 软件商店 -> 阿里云OSS -> 安装 -> 设置
# 填入阿里云OSS相关数据
# 保存路径:/backup
# 确认

# 宝塔 -> 计划任务 -> 添加任务
# 任务类型:备份数据库
# 执行周期:每天 4:30
# 数据库 备份到阿里云OSS 保留最新3份
# 同时保留本地备份
# 确定