mirror of
https://github.com/doocs/md.git
synced 2025-01-22 20:04:39 +08:00
feat: add support for Cloudflare R2 using AWS S3 API (#484)
All checks were successful
Build and Deploy / build-and-deploy (push) Has been skipped
All checks were successful
Build and Deploy / build-and-deploy (push) Has been skipped
This commit is contained in:
parent
1d6ab54091
commit
f10c5e665f
@ -44,7 +44,7 @@ Markdown 文档自动即时渲染为微信图文,让你不再为微信文章
|
||||
## 目前支持哪些图床
|
||||
|
||||
| # | 图床 | 使用时是否需要配置 | 备注 |
|
||||
| --- | ----------------------------------------------- | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
||||
| --- | ------------------------------------------------------ | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 1 | 默认 | 否 | - |
|
||||
| 2 | [GitHub](https://github.com) | 配置 `Repo`、`Token` 参数 | [如何获取 GitHub token?](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) |
|
||||
| 3 | [阿里云](https://www.aliyun.com/product/oss) | 配置 `AccessKey ID`、`AccessKey Secret`、`Bucket`、`Region` 参数 | [如何使用阿里云 OSS?](https://help.aliyun.com/document_detail/31883.html) |
|
||||
@ -52,7 +52,8 @@ Markdown 文档自动即时渲染为微信图文,让你不再为微信文章
|
||||
| 5 | [七牛云](https://www.qiniu.com/products/kodo) | 配置 `AccessKey`、`SecretKey`、`Bucket`、`Domain`、`Region` 参数 | [如何使用七牛云 Kodo?](https://developer.qiniu.com/kodo) |
|
||||
| 6 | [MinIO](https://min.io/) | 配置 `Endpoint`、`Port`、`UseSSL`、`Bucket`、`AccessKey`、`SecretKey` 参数 | [如何使用 MinIO?](http://docs.minio.org.cn/docs/master/) |
|
||||
| 7 | [公众号](https://mp.weixin.qq.com/) | 配置 `appID`、`appsecret`、`代理域名` 参数 | [如何获取公众号开发者 ID 密码?](https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Getting_Started_Guide.html) |
|
||||
| 8 | 自定义上传 | 是 | [如何自定义上传?](#自定义上传逻辑) |
|
||||
| 8 | [Cloudflare R2](https://developers.cloudflare.com/r2/) | 配置 `AccountId`、`AccessKey`、`SecretKey`、`Bucket`、`Domain` 参数 | [如何使用 S3 API 操作 R2](https://developers.cloudflare.com/r2/api/s3/api/) |
|
||||
| 9 | 自定义上传 | 是 | [如何自定义上传?](#自定义上传逻辑) |
|
||||
|
||||
![demo1](https://cdn-doocs.oss-cn-shenzhen.aliyuncs.com/gh/doocs/md/images/demo1.gif)
|
||||
|
||||
|
1645
package-lock.json
generated
1645
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -21,6 +21,7 @@
|
||||
"postinstall": "simple-git-hooks && wxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.716.0",
|
||||
"@vueuse/core": "^12.0.0",
|
||||
"axios": "^1.7.8",
|
||||
"buffer-from": "^1.1.2",
|
||||
|
@ -56,6 +56,15 @@ const minioOSS = ref({
|
||||
secretKey: ``,
|
||||
})
|
||||
|
||||
const formR2 = ref({
|
||||
accountId: ``,
|
||||
accessKey: ``,
|
||||
secretKey: ``,
|
||||
bucket: ``,
|
||||
domain: ``,
|
||||
path: ``,
|
||||
})
|
||||
|
||||
const formMp = ref({
|
||||
proxyOrigin: ``,
|
||||
appID: ``,
|
||||
@ -96,6 +105,10 @@ const options = [
|
||||
value: `mp`,
|
||||
label: `公众号图床`,
|
||||
},
|
||||
{
|
||||
value: `r2`,
|
||||
label: `Cloudflare R2`,
|
||||
},
|
||||
{
|
||||
value: `formCustom`,
|
||||
label: `自定义代码`,
|
||||
@ -125,6 +138,9 @@ onBeforeMount(() => {
|
||||
if (localStorage.getItem(`minioConfig`)) {
|
||||
minioOSS.value = JSON.parse(localStorage.getItem(`minioConfig`)!)
|
||||
}
|
||||
if (localStorage.getItem(`r2Config`)) {
|
||||
formR2.value = JSON.parse(localStorage.getItem(`r2Config`)!)
|
||||
}
|
||||
if (localStorage.getItem(`imgHost`)) {
|
||||
imgHost.value = localStorage.getItem(`imgHost`)!
|
||||
}
|
||||
@ -220,6 +236,23 @@ function saveQiniuConfiguration() {
|
||||
toast.success(`保存成功`)
|
||||
}
|
||||
|
||||
function saveR2Configuration() {
|
||||
if (
|
||||
!(
|
||||
formR2.value.accountId
|
||||
&& formR2.value.accessKey
|
||||
&& formR2.value.secretKey
|
||||
&& formR2.value.bucket
|
||||
&& formR2.value.domain
|
||||
)
|
||||
) {
|
||||
toast.error(`Cloudflare R2参数配置不全`)
|
||||
return
|
||||
}
|
||||
localStorage.setItem(`r2Config`, JSON.stringify(formR2.value))
|
||||
toast.success(`保存成功`)
|
||||
}
|
||||
|
||||
function saveMpConfiguration() {
|
||||
if (
|
||||
!(
|
||||
@ -315,6 +348,9 @@ function onDrop(e: DragEvent) {
|
||||
<TabsTrigger value="mp">
|
||||
公众号图床
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="r2">
|
||||
Cloudflare R2
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="formCustom">
|
||||
自定义代码
|
||||
</TabsTrigger>
|
||||
@ -689,6 +725,58 @@ function onDrop(e: DragEvent) {
|
||||
</FormItem>
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="r2">
|
||||
<div class="space-y-4">
|
||||
<FormItem label="AccountId" required>
|
||||
<Input v-model.trim="formR2.accountId" placeholder="如: 0030f123e55a57546f4c281c564e560" class="min-w-[350px]" />
|
||||
</FormItem>
|
||||
<FormItem label="AccessKey" required>
|
||||
<Input v-model.trim="formR2.accessKey" placeholder="如: 358090b3a12824a6b0787gae7ad0fc72" />
|
||||
</FormItem>
|
||||
<FormItem label="SecretKey" required>
|
||||
<Input
|
||||
v-model.trim="formR2.secretKey" type="password"
|
||||
placeholder="如: c1c4dbcb0b6b785ac6633422a06dff3dac055fe74fe40xj1b5c5fcf1bf128010"
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label="Bucket" required>
|
||||
<Input v-model.trim="formR2.bucket" placeholder="如:md" />
|
||||
</FormItem>
|
||||
<FormItem label="域名" required>
|
||||
<Input v-model.trim="formR2.domain" placeholder="如:https://oss.example.com" />
|
||||
</FormItem>
|
||||
<FormItem label="存储路径">
|
||||
<Input v-model.trim="formR2.path" placeholder="如:img,可不填,默认为根目录" />
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<div class="flex flex-col items-start">
|
||||
<Button
|
||||
variant="link"
|
||||
class="p-0"
|
||||
as="a"
|
||||
href="https://developers.cloudflare.com/r2/api/s3/api/"
|
||||
target="_blank"
|
||||
>
|
||||
如何使用 S3 API 操作 Cloudflare R2
|
||||
</Button>
|
||||
<Button
|
||||
variant="link"
|
||||
class="p-0"
|
||||
as="a"
|
||||
href="https://developers.cloudflare.com/r2/buckets/cors/"
|
||||
target="_blank"
|
||||
>
|
||||
如何设置跨域(CORS)
|
||||
</Button>
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem>
|
||||
<Button @click="saveR2Configuration">
|
||||
保存配置
|
||||
</Button>
|
||||
</FormItem>
|
||||
</div>
|
||||
</TabsContent>
|
||||
<TabsContent value="formCustom">
|
||||
<CustomUploadForm />
|
||||
</TabsContent>
|
||||
|
@ -3,6 +3,7 @@ import fetch from '@/utils/fetch'
|
||||
import * as tokenTools from '@/utils/tokenTools'
|
||||
|
||||
import { base64encode, safe64, utf16to8 } from '@/utils/tokenTools'
|
||||
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3'
|
||||
import Buffer from 'buffer-from'
|
||||
import COS from 'cos-js-sdk-v5'
|
||||
import CryptoJS from 'crypto-js'
|
||||
@ -376,6 +377,33 @@ async function mpFileUpload(file: File) {
|
||||
})
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Cloudflare R2 File Upload
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
async function r2Upload(file: File) {
|
||||
const { accountId, accessKey, secretKey, bucket, path, domain } = JSON.parse(
|
||||
localStorage.getItem(`r2Config`)!,
|
||||
)
|
||||
const dir = path ? `${path}/` : ``
|
||||
const filename = dir + getDateFilename(file.name)
|
||||
const client = new S3Client({ region: `auto`, endpoint: `https://${accountId}.r2.cloudflarestorage.com`, credentials: { accessKeyId: accessKey, secretAccessKey: secretKey } })
|
||||
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const putObjectCommand = new PutObjectCommand({
|
||||
Bucket: bucket,
|
||||
Key: filename,
|
||||
ContentType: file.type,
|
||||
Body: file,
|
||||
})
|
||||
client.send(putObjectCommand).then(() => {
|
||||
resolve(`${domain}/${filename}`)
|
||||
}).catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// formCustom File Upload
|
||||
// -----------------------------------------------------------------------
|
||||
@ -433,6 +461,8 @@ function fileUpload(content: string, file: File) {
|
||||
return ghFileUpload(content, file.name)
|
||||
case `mp`:
|
||||
return mpFileUpload(file)
|
||||
case `r2`:
|
||||
return r2Upload(file)
|
||||
case `formCustom`:
|
||||
return formCustomUpload(content, file)
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user