sdk接入oss

104 阅读3分钟

前言

oss的前置知识

oss接入官方文档

node接入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: 探索分片上传