前言
oss的前置知识
小小说明: 使用node做一些处理之前,我们先确保node的版本问题,以往的开发经验而言,很多次都是因为node版本问题, 而导致有一些依赖包没办法处理, 所以在阅读文档时稍微注意一下当前使用的node版本,然后我们选择的时候尽量就 >=文档中的版本且持久支持的版本。
文档中已经详细介绍了oss,那oss本质就是一个存储对象服务器, 我们把我们的资源文件等存储到服务器上,然后我们通过url就可以访问了, 文档中给出了我们如何存,以及如何取,在存与取的过程中可以做哪些事操作和限制。
官方的使用
理解一些概念
存储空间Bucket: 是存储对象的容器,对象都隶属于存储空间
如何存
如何取
着手处理上传
主要有两个链路: 上传和反显 上传链路: 上传采用client端调用server node接口获取要上传的url路径,然后再调用http请求把内容进行上传,然后把ossKey即path+name落库。
反显链路: 目前可直接通过后端返回的url通过a标签直接访问
分解动作
上传组件
使用ProComponent的ProFormUploadButton组件
const Host = 'xxxxx'
/**
* 调用node的接口
* 入参:文件名称
* 返回值: oss的url
*/
function uploadImages(params: IUploadImg): Promise<any> {
return httpRequest.post(Host + '/api/uploadFiles', params);
}
//自定义上传行为
export const customRequest = (options: any) => {
const { file, onSuccess, onError } = options;
const { name: filename } = file;
uploadImages({ filename }).then((url: string) => {
const contentType = 'application/octet-stream';
const body = new Blob([file], { type: contentType });
fetch(url, {
method: 'PUT',
headers: new Headers({ 'Content-Type': 'application/octet-stream' }),
body
})
.then(() => {
onSuccess();
})
.catch((e) => {
// message.error('文件上传失败!');
onError(e);
});
});
};
//点击提交表单的时候获取到上传的图片信息
const submit = (_form)=>{
_form?.uploadInfo //为一个数组,数组中的每一个元素为上传的每一个图片的信息,具体的字段参考:https://4x-ant-design.antgroup.com/components/upload-cn/的api的uploadFile部分
}
//预览操作 可以参考官网使用, 这里完全参考官网的代码
const [previewOpen, setPreviewOpen] = useState(false);
const [previewImage, setPreviewImage] = useState('');
const [previewTitle, setPreviewTitle] = useState('预览图片');
const handleCancel = () => setPreviewOpen(false);
const getBase64 = (file: RcFile): Promise<string> =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => resolve(reader.result as string);
reader.onerror = (error) => reject(error);
});
const handlePreview = async (file: UploadFile) => {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj as RcFile);
}
setPreviewImage(file.url || (file.preview as string));
setPreviewOpen(true);
};
<div>
<DrawerForm
title="阶段"
open={open}
onOpenChange={setOpen}
drawerProps={{ destroyOnClose: true }}
onFinish={submit}
layout="horizontal"
labelAlign="right"
grid={true}
rowProps={{
gutter: 24
}}
colProps={{
span: 24
}}
labelCol={{ span: 6 }}
wrapperCol={{ span: 18 }}
//传入props初始值平铺
initialValues={{ ...init, ...detail}}
>
<ProFormUploadButton
name="uploadInfo"
label="信息收集"
max={1} //该属性控制上传个数,最多上传一个
fieldProps={{
name: 'uploadInfo',
customRequest ,//自定义上传行为
multiple: true,
accept: 'image/*,.png,.jpg',//过滤操作,只能上传.png .jpg结尾的文件
onPreview:handlePreview,//图片上传后的预览
}}
/>
</DrawerForm>
//预览的modal
<Modal
open={previewOpen}
title={previewTitle}
footer={null}
onCancel={handleCancel}
>
<img alt="example" style={{ width: '100%' }} src={previewImage} />
</Modal>
</div>
node中上传接口处理
@Provide()
export class CommonApiHandler {
@Inject()
ctx!: FaaSContext;
@Config("oss")
ossConfig!: any;
@ServerlessTrigger(ServerlessTriggerType.HTTP, {
path: "/api/uploadFiles",
method: "post",
})
async uploadFiles() {
const { filename } = this.ctx.request.body;
let dir = "crm/"; // OSS 文件根目录
const ossClient = new OSS(this.ossConfig);
const url = ossClient.signatureUrl(
dir + new Date().getTime() + decodeURIComponent(filename),
{
method: "PUT",
"Content-Type": "application/octet-stream",
}
);
return url;
}
}
整体的代码
项目名称/server/src/
/config下config.daily.ts、config.default.ts、config.local.ts、config.pre.ts 更多字段的配置参考 midway多环境配置
/config/config.daily.ts
export default{
oss:{
endpoint:'',//访问的域名
accessKeyId:'', //获取访问凭证
accessKeysecret:'', //获取访问凭证
bucket:'',//在哪个空间获取对象
secure:true,//上传的url是https 需要配置该属性
}
}
/functions/api
import { Context as FaaSContext } from "@midwayjs/faas";
import {
Config,
Inject,
Provide,
ServerlessTrigger,
ServerlessTriggerType,
} from "@midwayjs/decorator";
const OSS = require("ali-oss");
@Provide()
export class CommonApiHandler {
@Inject()
ctx!: FaaSContext;
@Config("oss")
ossConfig!: any;
@ServerlessTrigger(ServerlessTriggerType.HTTP, {
path: "/api/uploadFiles",
method: "post",
})
async uploadFiles() {
const { filename } = this.ctx.request.body;
let dir = "crm/"; // OSS 文件根目录
const ossClient = new OSS(this.ossConfig);
const url = ossClient.signatureUrl(
dir + new Date().getTime() + decodeURIComponent(filename),
{
method: "PUT",
"Content-Type": "application/octet-stream",
}
);
return url;
}
}
/interface/api.ts 一般会有接口文档,可以很方便的看到所有的接口
/service/xx.ts 这里一般是HSF服务的具体调用,或者可以理解为数据库调用等处理
TODO: 探索分片上传