☰
HedgeDoc 使用 WebDAV 作为图片存储后端:环境变量配置与 Nextcloud 实战指南
2026/9/28 2:55:14 网站建设 项目流程
  • 后端
  • 前端
  • 云原生

【免费下载链接】hedgedoc

HedgeDoc - Ideas grow better together

项目地址:https://gitcode.com/gh_mirrors/he/hedgedoc
点击查看免费下载

HedgeDoc 支持将笔记中的图片上传存储到多种后端(本地文件系统、S3、Azure Blob、imgur、WebDAV),其中 WebDAV 方案允许你复用任意支持 WebDAV 协议的服务器来托管上传文件。本文将基于仓库文档与源码,完整讲解HD_MEDIA_BACKEND_WEBDAV_*三个环境变量的含义与取值规则,并以 Nextcloud 为例给出从创建应用密码到验证上传的完整实操步骤。读完本文,你可以独立为 HedgeDoc 配置一套基于 WebDAV/Nextcloud 的图片存储服务。

一、WebDAV 媒体后端的工作原理

在 HedgeDoc 中,媒体(Media)指与笔记关联的上传内容,目前仅支持图片。所有存储后端都必须实现同一个接口,包含三个方法(见 backend/src/media/media-backend.interface.ts 与设计文档 docs/content/concepts/media.md):

  • saveFile(uuid, buffer, fileType):保存文件,并返回一段字符串化的元数据供数据库留存,该元数据只在本后端内部使用;
  • deleteFile(uuid, metadata):根据 UUID 与元数据删除远端文件;
  • getFileUrl(uuid, metadata):返回该文件对外可访问的 URL。

对于 WebDAV 后端,HedgeDoc 会在启动时通过PROPFIND请求探测目标目录是否可访问(见 webdav-backend.ts),若请求失败会直接抛错,提示Can't access <url>。因此,配置完成并启动后,WebDAV 服务器必须允许 HedgeDoc 以配置的凭据访问目标目录。

后端的选择在 backend/src/media/media.module.ts 中注册,由 MediaService 依据HD_MEDIA_BACKEND_TYPE的值(filesystem/azure/imgur/s3/webdav)决定实例化哪一个后端。上传时MediaService.saveFile会先对文件做 MIME 类型白名单校验(仅允许 apng、bmp、gif、heif/heic、jpeg、png、svg、tiff、webp,见 media.service.ts),再调用WebdavBackend.saveFile完成写入。

二、核心配置:三个 WebDAV 环境变量

在 HedgeDoc 中,所有配置均通过环境变量(或根目录.env文件)注入。WebDAV 后端只需在配置中加入以下三行(<CONNECTION_STRING>、<UPLOAD_DIR>、<PUBLIC_URL>需替换为实际值):

HD_MEDIA_BACKEND_TYPE="webdav" HD_MEDIA_BACKEND_WEBDAV_CONNECTION_STRING="<CONNECTION_STRING>" HD_MEDIA_BACKEND_WEBDAV_UPLOAD_DIR="<UPLOAD_DIR>" HD_MEDIA_BACKEND_WEBDAV_PUBLIC_URL="<PUBLIC_URL>"

对应地,仓库中的配置解析(backend/src/config/media.config.ts)对这三个变量有明确的校验规则,这与使用体验直接相关:

环境变量说明校验要求是否必填
HD_MEDIA_BACKEND_TYPE媒体后端类型,取webdav时启用本后端必须与五种后端类型之一精确匹配必填
HD_MEDIA_BACKEND_WEBDAV_CONNECTION_STRINGWebDAV 服务器的连接地址,含身份信息必须是一个合法的 URL(zod 的z.string().url())必填
HD_MEDIA_BACKEND_WEBDAV_UPLOAD_DIR上传目标目录;省略则直接上传到 WebDAV 服务器根目录可选字符串,可为空可选
HD_MEDIA_BACKEND_WEBDAV_PUBLIC_URLHedgeDoc 对外访问上传文件的 URL 前缀必须是一个合法的 URL必填

配置解析使用 zod 校验(同文件中z.discriminatedUnion('type', [...])定义),一旦HD_MEDIA_BACKEND_TYPE之外的关键值非法或缺失,启动时会打印格式化的错误信息并退出,避免带病运行。

2.1 CONNECTION_STRING:连接地址与身份凭据

<CONNECTION_STRING>采用 WebDAV 常见的schema://user:password@url形式,把用户名与密码(如有需要)直接内嵌进 URL,例如:

https://TestUser:passw0rd@cloud.example.com/remote.php/dav/files/TestUser/

从源码看,WebdavBackend 会解析该 URL:先以完整连接串为基准,若同时配置了非空的UPLOAD_DIR,则把目录拼接在连接串之后作为最终上传基址;随后用url.username与url.password生成 HTTP Basic Auth 请求头(Basic base64(username:password),见 webdav-backend.ts)。

2.2 UPLOAD_DIR:指定上传目录(可省略)

<UPLOAD_DIR>用于指定上传的目标文件夹,例如HedgeDoc。它不是必填项——如果不设置(即完全不写该变量),HedgeDoc 会把文件直接上传到 WebDAV 服务器的根目录。源码中的对应逻辑是:仅当uploadDir存在且非空字符串时才拼接目录(webdav-backend.ts)。

2.3 PUBLIC_URL:对外访问 URL 前缀

<PUBLIC_URL>指定 HedgeDoc 访问上传文件所用的 URL 前缀。文件名会被直接追加到该前缀之后。例如PUBLIC_URL为https://dav.example.com、文件名为test.png时,访问地址即为https://dav.example.com/test.png。

这与源码行为完全一致:getFileUrl 从数据库元数据中取出文件名,再将其拼接到publicUrl之后返回;MediaService.getFileResponse 对 WebDAV 这类后端返回{ type: 'redirect', url },由媒体重定向控制器(backend/src/media-redirect/media-redirect.controller.ts)将浏览器 302 到该地址。因此PUBLIC_URL必须指向一个能让浏览器直接下载到图片的公开地址。

三、上传与删除的底层行为

理解后端的 HTTP 细节有助于排查故障。WebdavBackend内部使用fetch与 WebDAV 服务器交互:

  • 上传(saveFile):以PUT方法请求baseUrl/<uuid>.<扩展名>,携带Authorization、Content-Type: application/octet-stream与准确的Content-Length,并设置If-None-Match: *头,保证不会覆盖已存在的文件(见 webdav-backend.ts)。上传成功后,后端把{"file":"<uuid>.<ext>"}这样的 JSON 字符串作为 backendData 写入数据库的media_upload表;
  • 删除(deleteFile):以DELETE方法请求baseUrl/<文件名>(见 webdav-backend.ts);
  • 访问(getFileUrl):如上所述,仅拼接publicUrl与文件名,不发起请求。

需要特别注意的是:CONNECTION_STRING中携带的用户名/密码会出现在配置文件里,因此官方文档建议为上传单独创建一个专用 WebDAV 用户,并尽量使用应用密码(App Password)而不是主密码。

四、Nextcloud 实战配置(完整步骤)

以 Nextcloud 作为 WebDAV 服务器是最常见的用法。以下步骤以 Nextcloud 21(2021 年 4 月撰写指南时的版本)为例,演示用户名为TestUser、生成的应用密码为passw0rd的完整配置链路。由于连接串中包含用户名与密码,强烈建议使用一个专用 Nextcloud 用户来承担上传任务。

  1. 创建应用密码:登录 Nextcloud 后进入Settings>Security,由 Nextcloud 生成一个应用密码(本例假设为passw0rd)。
  2. 创建上传文件夹:在文件(Files)应用中新建一个文件夹用于存放上传内容,例如HedgeDoc。
  3. 共享该文件夹:右键/菜单共享刚创建的文件夹。默认配置为Read Only(只读),本指南按此假设展开;选择Allow upload and editing(允许上传和编辑)同样可行。
  4. 获取共享链接:创建共享后链接通常已在剪贴板,否则点击Share link一行末尾的剪贴板图标复制。本例假设共享链接为https://cloud.example.com/s/some-id。
  5. 拼接下载参数:在该链接末尾追加/download?path=%2F&files=,得到https://cloud.example.com/s/some-id/download?path=%2F&files=。这正是之后PUBLIC_URL的取值,HedgeDoc 会把文件名追加到其后,使图片通过共享链接的下载端点对外提供。
  6. 获取 Nextcloud 的 WebDAV 地址:在文件应用的左下角,位于Settings>WebDAV处。本例假设为https://cloud.example.com/remote.php/dav/files/TestUser/。
  7. 拼入登录信息:在 URL 协议(通常是https://)与 URL 其余部分(本例为cloud.example.com/remote.php/dav/files/TestUser/)之间插入username:password@,得到https://TestUser:passw0rd@cloud.example.com/remote.php/dav/files/TestUser/。这就是CONNECTION_STRING。
  8. 配置 HedgeDoc:
HD_MEDIA_BACKEND_TYPE="webdav" HD_MEDIA_BACKEND_WEBDAV_CONNECTION_STRING="https://TestUser:passw0rd@cloud.example.com/remote.php/dav/files/TestUser/" HD_MEDIA_BACKEND_WEBDAV_UPLOAD_DIR="HedgeDoc" HD_MEDIA_BACKEND_WEBDAV_PUBLIC_URL="https://cloud.example.com/s/some-id/download?path=%2F&files="

完成上述配置后重启 HedgeDoc 服务,即可开始使用由 Nextcloud WebDAV 支撑的图片上传:上传时文件以<uuid>.<扩展名>的命名写入TestUser的HedgeDoc目录,笔记中的图片通过共享链接的下载地址对外展示。

五、验证与常见问题

  • 启动即验证:WebdavBackend构造时会对baseUrl发起一次PROPFIND(Depth: 0)请求,非 2xx 响应或网络失败都会导致启动报错Can't access <url>。若服务起不来,优先检查连接串的协议、主机、目录与凭据。
  • PUBLIC_URL 必须可公开访问:它仅用于拼 URL,HedgeDoc 自身不代理图片字节流,而是返回 302 重定向。请确认浏览器可以直接访问PUBLIC_URL + 文件名。
  • 文件不会被覆盖:上传请求带If-None-Match: *,同名文件(UUID 冲突)会失败而不是覆盖,确保历史图片引用不被破坏。
  • 目录与凭据的转义:用户名、密码若含@、:、/等特殊字符,需按 URL 编码规则转义,否则 URL 解析与 Basic Auth 会出错。
  • 配置格式要求:CONNECTION_STRING与PUBLIC_URL必须是合法 URL,UPLOAD_DIR可省略;若省略上传目录,文件将落在 WebDAV 服务器根目录。

六、相关资源

  • 官方文档:docs/content/references/config/media/webdav.md(本文的原始依据)
  • 配置解析与校验:backend/src/config/media.config.ts
  • WebDAV 后端实现:backend/src/media/backends/webdav-backend.ts
  • 媒体后端统一接口:backend/src/media/media-backend.interface.ts
  • 媒体服务与后端选择逻辑:backend/src/media/media.service.ts
  • 后端注册:backend/src/media/media.module.ts
  • 媒体设计文档:docs/content/concepts/media.md
  • 环境变量总体说明:docs/content/references/config/index.md
  • 后端
  • 前端
  • 云原生

【免费下载链接】hedgedoc

HedgeDoc - Ideas grow better together

项目地址:https://gitcode.com/gh_mirrors/he/hedgedoc
点击查看免费下载

相关推荐

上一篇:sd-forge-layerdiffusion开发者指南:代码架构与自定义扩展开发
下一篇:代码辅助every-chatgpt-gui:专为开发者设计的ChatGPT界面

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询