提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
华为OBS存储使用Nodejs版本
前言
最近在一个新的项目上使用了nodejs,使用的框架是Fastify,其中需要上传附件到华为的OBS中,按照官方文档开发也是遇到了一些问题。
一、 获取AK和SK
购买后从官网获取
略
具体过程可以参考官方文档(https://support.huaweicloud.com/sdk-nodejs-devg-obs/obs_29_0102.html)
二、过程
1 引入和注册插件
1.1 安装插件
npm install esdk-obs-nodejs
1.2 新建obs.js文件
// 引入obs库
// 使用npm安装
var ObsClient = require('esdk-obs-nodejs');
// 如果需要代理可以安装使用
// var ProxyAgent = require('proxy-agent');
// 使用源码安装(乳鸽)
// var ObsClient = require('./lib/obs');
const config = require('../config/config');
// 创建ObsClient实例
const obsClient = new ObsClient({
//推荐通过环境变量获取AKSK,这里也可以使用其他外部引入方式传入,如果使用硬编码可能会存在泄露风险。
//您可以登录访问管理控制台获取访问密钥AK/SK,获取方式请参见https://support.huaweicloud.com/usermanual-ca/ca_01_0003.html
access_key_id: `${config.huaweiObs['AccessKeyId']}`,
secret_access_key: `${config.huaweiObs['SecretAccessKey']}`,
//这里以华北-北京四为例,其他地区请按实际情况填写
// 写你自己的地址
server: 'https://obs.cn-north-4.myhuaweicloud.com',
max_retry_count : 1,
timeout : 200,
ssl_verify : false,
long_conn_param : 0,
// http_agent : new ProxyAgent('*** Provide your Network proxy ***') // 配置网络代理
});
module.exports = obsClient;
注:这里的server地址不需要加上桶名,和调用华为OBS的API的方式不同,调API需要在使用的地址上拼接上桶名,但是nodejs使用的sdk的方式,桶名作为参数进行使用。
其中的配置config,我写在了config.js中
'use strict'
const dotenv = require('dotenv');
const path = require('path');
const envFile = process.env.NODE_ENV ? `.env.${process.env.NODE_ENV}` : '.env';
dotenv.config({ path: path.resolve(process.cwd(), envFile) });
const config = {
huaweiObs: {
BucketName: "your BucketName",
AccessKeyId: "your AccessKeyId",
SecretAccessKey: "your SecretAccessKey",
},
}
module.exports = config;
1.3 注册插件
由于的目录结构如图所示
因此在注册插件时使用的的方式时
在app.js文件中
'use strict'
const path = require('node:path')
const AutoLoad = require('@fastify/autoload')
const yourPlugin = require('/your_path/yourPlugin');
module.exports = async function (fastify, opts) {
fastify.register(AutoLoad, {
dir: path.join(__dirname, 'plugins'),
options: Object.assign({}, opts)
})
fastify.register(AutoLoad, {
dir: path.join(__dirname, 'routes'),
options: Object.assign({}, opts)
})
// fastify.decorate('currentUser', null);
//也可以采用直接引入注册的方式
fastify.register(yourPlugin)
}
2 文件操作
在huaweiObsLib.js中统一处理obs的上传文件操作。
2.1 文件上传
//huaweiObsLib.js
'use strict'
const obsClient = require('../plugins/obs')
// 如果Obs桶中是按照目录来分类的话,需要设置文件夹目录
const obs_path ="folder_catalogue/"
const BucketName = 'BucketName ' // 可以取配置中的桶名
async function uploadFile(file) {
try {
const ext = file.filename.split(".")[1].toString() || ''
const new_filename = `${file.uuid}.${ext}`
const result = await obsClient.putObject({
Bucket : BucketName,
Key : obs_path + new_filename,
// SourceFile : file.data, // localfile为待上传的本地文件路径,需要指定到具体的文件名
// Metadata: { meta1: 'value1', meta2: 'value2'},
Body: file.data,
ContentType: file.file_type
})
if (result.CommonMsg.Status < 300) {
return { status: true, statusCode: result.CommonMsg.Status, data: result.InterfaceResult };
} else {
return { status: false, statusCode: result.CommonMsg.Status, data: result.CommonMsg.Message };
}
} catch (err) {
return { status: false, statusCode: 500, data: err }
}
}
在请求接口中的调用,可以直接写在路由文件中,也可以写在控制器中,这基于不同的路由书写方式。
const Attachment = require('../models/Attachment')
const huaweiObsLib= require('../lib/huaweiObsLib')
module.exports = async function (fastify, opts) {
fastify.get('/upload_file', async function (request, reply) {
try {
const data = await request.file();
const uuid = crypto.randomBytes(16).toString('hex')
let fileSize = data.file.bytesRead
const attachment = new Attachment({filename: data.filename, metadata: data.mimetype, length: fileSize, uuid:uuid})
const res = await huaweiObsLib.uploadFile({data: data.file, uuid: uuid, file_type: data.mimetype, filename: data.filename})
if (res.statusCode < 300) {
await attachment.save()
return reply.send({ status: true, statusCode: 200, message: 'File uploaded successfully', data: info });
} else {
return reply.status(res.statusCode).send({ status: false, statusCode: res.statusCode, message: res.message });
}
} catch (error) {
throw boom.boomify(error);
}
})
}
2.2 文件下载
//huaweiObsLib.js
'use strict'
const obsClient = require('../plugins/obs')
// 如果Obs桶中是按照目录来分类的话,需要设置文件夹目录
const obs_path ="folder_catalogue/"
const BucketName = 'BucketName ' // 可以取配置中的桶名
async function downloadFile(file) {
try {
const ext = file.filename.split(".")[1].toString() || ''
const new_filename = `${file.uuid}.${ext}`
const result = await obsClient.getObject({ Bucket: BucketName, Key: obs_path + new_filename,
// 是否将对象以流(stream.Readable)的形式返回。
SaveAsStream: true,
// SaveByType: 'file'
})
if (result.CommonMsg.Status < 300) {
return { status: true, statusCode: result.CommonMsg.Status, data: result.InterfaceResult };
} else {
return { status: false, statusCode: result.CommonMsg.Status, data: result.CommonMsg.Message };
}
} catch (err) {
return { status: false, statusCode: 500, data: err }
}
}
在请求接口中的调用
const Attachment = require('../models/Attachment')
const huaweiObsLib= require('../lib/huaweiObsLib')
module.exports = async function (fastify, opts) {
fastify.get('/download_file', async function (request, reply) {
try {
onst id = request.query.id
const attachment = await Attachment.findById(id)
if (!attachment) {
return reply.status(404).send({ statusCode: 404, message: 'File not found' });
}
const res = await huaweiObsLib.downloadFile({uuid: attachment.uuid, filename: attachment.filename})
if (res.statusCode < 300) {
reply.header('Content-Type', res.data.ContentType);
// const base64Data = Buffer.from(res.data.Content).toString('base64');
// const dataUrl = `data:${res.data.ContentType};base64,${base64Data}`;
return reply.send(res.data.Content);
} else {
return reply.status(res.statusCode).send({ status: false, statusCode: res.statusCode, message: res.message });
}
} catch (error) {
throw boom.boomify(error);
}
})
}
2.3 文件删除
//huaweiObsLib.js
'use strict'
const obsClient = require('../plugins/obs')
// 如果Obs桶中是按照目录来分类的话,需要设置文件夹目录
const obs_path ="folder_catalogue/"
const BucketName = 'BucketName ' // 可以取配置中的桶名
async function deleteFile(file) {
try {
const ext = file.filename.split(".")[1] || ''
const new_filename = `${file.uuid}.${ext}`
const result = await obsClient.deleteObject({
Bucket: BucketName,
Key: obs_path + new_filename
})
if (result.CommonMsg.Status < 300) {
return { status: true, statusCode: result.CommonMsg.Status, data: result.InterfaceResult };
} else {
return { status: false, statusCode: result.CommonMsg.Status, data: result.CommonMsg.Message };
}
} catch (err) {
return { status: false, statusCode: 500, data: err }
}
}
在请求接口中的调用
const Attachment = require('../models/Attachment')
const huaweiObsLib= require('../lib/huaweiObsLib')
module.exports = async function (fastify, opts) {
fastify.get('/delete_file', async function (request, reply) {
try {
const id = request.query.id
const attachment = await Attachment.findById(id)
if (!attachment) {
return reply.status(404).send({ statusCode: 404, message: 'File not found' });
}
const res = await huaweiObsLib.deleteFile({uuid: uuid, filename: filename})
if (res.statusCode < 300) {
await this.findByIdAndDelete(id)
return reply.status(res.statusCode).send(res);
} else {
return reply.status(res.statusCode).send({ status: false, statusCode: res.statusCode, message: res.message });
}
} catch (error) {
throw boom.boomify(error);
}
})
}
三、路由
Fastify项目的路由注册方式的记录
在app.js中注册路由routes
'use strict'
const path = require('node:path')
const AutoLoad = require('@fastify/autoload')
const yourPlugin = require('/your_path/yourPlugin');
module.exports = async function (fastify, opts) {
fastify.register(AutoLoad, {
dir: path.join(__dirname, 'routes'),
options: Object.assign({}, opts)
})
}
1
'use strict'
module.exports = async function (fastify, opts) {
fastify.get('/users', async function (request, reply) {
return { status: true, statusCode: 200, message: 'Hello, World!' }
})
}
2
'use strict'
const boom = require('boom')
const usersController = require('../controllers/usersController')
const routes = [
{
method: 'get',
url: '/login',
handler: usersController.login
},
{
method: 'get',
url: '/users/index',
handler: usersController.getUser
},
]
module.exports = async function (fastify, opts) {
routes.forEach((route, index) => {
fastify.route(route)
})
}