From c4235ad5053d6c10972d87343ed318be83451cc8 Mon Sep 17 00:00:00 2001 From: xw Date: Thu, 25 Nov 2021 11:54:29 +0800 Subject: [PATCH] feat: support unicloud private server (#99) --- mm.config.js | 41 ------------------ mm/.gitignore | 1 + mm/apiWeb.json | 4 ++ mm/mm.config.js | 57 +++++++++++++++++++++++++ mm/readme.md | 21 ++++++++++ mm/util.js | 109 ++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 7 files changed, 193 insertions(+), 42 deletions(-) delete mode 100644 mm.config.js create mode 100644 mm/.gitignore create mode 100644 mm/apiWeb.json create mode 100644 mm/mm.config.js create mode 100644 mm/readme.md create mode 100644 mm/util.js diff --git a/mm.config.js b/mm.config.js deleted file mode 100644 index 13503ec..0000000 --- a/mm.config.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * 配置说明请参考文档: - * https://hongqiye.com/doc/mockm/config/option.html - * @type {import('mockm/@types/config').Config} - */ -module.exports = (util) => { - const port = 9000 - return { - port, - api: { - async '/upload'(req, res) { - const multiparty = await util.toolObj.generate.initPackge(`multiparty`) - const form = new multiparty.Form({ - uploadDir: `./public/upload/`, - }) - form.parse(req, (err, fields = [], files) => { - const path = files.file[0].path.replace(/\\/g, `/`) - const url = `http://127.0.0.1:${port}/${path}` - res.json({ - msg: `上传成功`, - url, - }) - }) - }, - }, - static: [ - { // 测试 netlify 部署 - fileDir: `./dist`, - path: `/`, - }, - { // 测试 gitee/github 部署 - fileDir: `./dist`, - path: `/md`, - },, - { // 访问公共目录 - fileDir: `./public`, - path: `/public`, - }, - ], - } -} diff --git a/mm/.gitignore b/mm/.gitignore new file mode 100644 index 0000000..3522371 --- /dev/null +++ b/mm/.gitignore @@ -0,0 +1 @@ +httpData/ \ No newline at end of file diff --git a/mm/apiWeb.json b/mm/apiWeb.json new file mode 100644 index 0000000..b576de9 --- /dev/null +++ b/mm/apiWeb.json @@ -0,0 +1,4 @@ +{ + "paths": {}, + "disable": [] +} \ No newline at end of file diff --git a/mm/mm.config.js b/mm/mm.config.js new file mode 100644 index 0000000..57c3f29 --- /dev/null +++ b/mm/mm.config.js @@ -0,0 +1,57 @@ +const fs = require(`fs`) +const path = require(`path`) + +const { dcloud } = require(`./util.js`) + +// unicloud 服务空间配置 +const spaceInfo = { + spaceId: ``, + clientSecret: ``, +} + +/** + * 配置说明请参考文档: + * https://hongqiye.com/doc/mockm/config/option.html + * @type {import('mockm/@types/config').Config} + */ +module.exports = util => { + const port = 9000 + return { + port, + testPort: 9005, + replayPort: 9001, + watch: [`./util.js`], + api: { + async '/upload'(req, res) { + const multiparty = await util.toolObj.generate.initPackge(`multiparty`) + const form = new multiparty.Form({ + uploadDir: `../public/upload/`, + }) + form.parse(req, async (err, fields = [], files) => { + const file = files.file[0] + let url = `http://127.0.0.1:${port}/public/upload/${path.parse(file.path).base}` + try { + url = await dcloud(spaceInfo)({name: file.originalFilename, file: fs.createReadStream(file.path)}) + } catch (err) { + // console.log(err) + } + res.json({url}) + }) + }, + }, + static: [ + { // 测试 netlify 部署 + fileDir: `../dist`, + path: `/`, + }, + { // 测试 gitee/github 部署 + fileDir: `../dist`, + path: `/md`, + },, + { // 访问公共目录 + fileDir: `../public`, + path: `/public`, + }, + ], + } +} diff --git a/mm/readme.md b/mm/readme.md new file mode 100644 index 0000000..8c509ff --- /dev/null +++ b/mm/readme.md @@ -0,0 +1,21 @@ +# 说明 + +此目录是运行命令 `mm --template` 之后生成的 mockm 常用配置, 该命令做了以下事情: + +在运行目录的 package.json 的 scripts 中添加命令 `"mm": "npx mockm --cwd=mm"`, 如果没有 package.json 文件, 会自动创建. + +创建名为 mm 的目录, 文件说明如下, 如果存在则不覆盖: + +``` +mm/ + - api/ -- 手动创建的 api + - httpData/ -- 请求记录, 一般不提交到版本库 + - apiWeb.json -- 从 UI 界面上创建的接口信息 + - util.js -- 一些公用方法 + - mm.config.js -- mockm 的配置文件 +``` + +## 参考 +- [mm 代码仓库](https://github.com/wll8/mockm/) +- [mm 文档](https://hongqiye.com/doc/mockm/) +- [mockjs 文档](http://wll8.gitee.io/mockjs-examples/) \ No newline at end of file diff --git a/mm/util.js b/mm/util.js new file mode 100644 index 0000000..a069b1d --- /dev/null +++ b/mm/util.js @@ -0,0 +1,109 @@ +const fetch = require('node-fetch') +const FormData = require(`form-data`) + +function dcloud(spaceInfo) { + if(Boolean(spaceInfo.spaceId && spaceInfo.clientSecret) === false) { + throw new Error(`请填写 spaceInfo`) + } + + function sign(data, secret) { + const hmac = require(`crypto`).createHmac(`md5`, secret) + // 排序 obj 再转换为 key=val&key=val 的格式 + const str = Object.keys(data).sort().reduce((acc, cur) => `${acc}&${cur}=${data[cur]}`, ``).slice(1) + hmac.update(str) + return hmac.digest(`hex`) + } + + async function anonymousAuthorize() { + const data = { + method: `serverless.auth.user.anonymousAuthorize`, + params: `{}`, + spaceId: spaceInfo.spaceId, + timestamp: Date.now(), + } + return await fetch(`https://api.bspapp.com/client`, { + headers: { + 'x-serverless-sign': sign(data, spaceInfo.clientSecret), + }, + body: `{"method":"serverless.auth.user.anonymousAuthorize","params":"{}","spaceId":"${spaceInfo.spaceId}","timestamp":${data.timestamp}}`, + method: `POST`, + }).then((res) => res.json()) + } + + async function report({ id, token }) { + const reportReq = { + method: `serverless.file.resource.report`, + params: `{"id":"${id}"}`, + spaceId: spaceInfo.spaceId, + timestamp: Date.now(), + token: token, + } + return await fetch(`https://api.bspapp.com/client`, { + headers: { + 'x-basement-token': reportReq.token, + 'x-serverless-sign': sign(reportReq, spaceInfo.clientSecret), + }, + body: JSON.stringify(reportReq), + method: `POST`, + }).then((res) => res.json()) + } + + async function generateProximalSign({ name, token }) { + const data = { + method: `serverless.file.resource.generateProximalSign`, + params: `{"env":"public","filename":"${name}"}`, + spaceId: spaceInfo.spaceId, + timestamp: Date.now(), + token, + } + const res = await fetch(`https://api.bspapp.com/client`, { + headers: { + 'x-basement-token': data.token, + 'x-serverless-sign': sign(data, spaceInfo.clientSecret), + }, + body: JSON.stringify(data), + method: `POST`, + }).then((res) => res.json()) + return res + } + + async function upload({ data, file }) { + const formdata = new FormData() + Object.entries({ + 'Cache-Control': `max-age=2592000`, + 'Content-Disposition': `attachment`, + OSSAccessKeyId: data.accessKeyId, + Signature: data.signature, + host: data.host, + id: data.id, + key: data.ossPath, + policy: data.policy, + success_action_status: 200, + file, + }).forEach(([key, val]) => formdata.append(key, val)) + + return await fetch(`https://${data.host}`, { + headers: { + 'X-OSS-server-side-encrpytion': `AES256`, + }, + body: formdata, + method: `POST`, + }) + } + + async function uploadFile({ name = `unnamed.file`, file }) { + const token = (await anonymousAuthorize()).data.accessToken + const res = await generateProximalSign({ name, token }) + await upload({ data: res.data, file }) + await report({ id: res.data.id, token }) + const fileUrl = `https://${res.data.cdnDomain}/${res.data.ossPath}` + return fileUrl + } + + return uploadFile + +} + +module.exports = { + dcloud, +} diff --git a/package.json b/package.json index b85a724..6adc273 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "serve": "vue-cli-service serve", "build:h5-netlify": "cross-env SERVER_ENV=NETLIFY vue-cli-service build", "build": "vue-cli-service build", - "mm": "npx mockm" + "mm": "npx mockm --cwd=mm" }, "dependencies": { "@vue/shared": "^3.0.11",