WebDAVClient

webdav简单客户端,支持创建文件,列目录,读取文件,写入文件,删除文件,移动/复制文件,判断文件是否存在等

目前為 2025-10-31 提交的版本,檢視 最新版本

此腳本不應該直接安裝,它是一個供其他腳本使用的函式庫。欲使用本函式庫,請在腳本 metadata 寫上: // @require https://update.cn-greasyfork.org/scripts/554239/1687012/WebDAVClient.js

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

作者
wish king
版本
0.0.1.20251031133505
建立日期
2025-10-30
更新日期
2025-10-31
尺寸
14.2 KB
授權條款
未知

主要功能

这个 WebDAV 客户端实现了以下功能:

✅ exists(path) - 检查文件或目录是否存在

✅ createDirectory(path) - 创建目录(支持递归创建)

✅ getFileContents(path, options) - 获取文件内容(支持 text/binary/json 格式)

✅ putFileContents(path, content, options) - 上传文件a内容(支持覆盖选项)

✅ getDirectoryContents(path) - 列出目录内容(支持扁平化返回子目录)

✅ deleteFile(path) - 删除文件或目录

✅ moveFile(fromPath, toPath) - 移动/重命名文件

✅ copyFile(fromPath, toPath) - 复制文件

特性

🔐 支持 Basic Authentication

🔄 自动处理路径标准化

📁 支持递归创建目录和扁平化返回子目录

⚠️ 完善的错误处理


WebDAVClient 使用文档(中文版 by chatgpt5)

下面是你当前 WebDAVClient 库的完整使用说明、示例、注意事项与常见问题排查。文档面向在 Tampermonkey / Userscript 环境里使用该客户端的场景(库实现依赖 GM_xmlhttpRequest)。


概览

WebDAVClient 是一个轻量的 WebDAV 客户端类,封装了常用的 WebDAV 操作:列目录、读取/写入文件、创建目录、删除/移动/复制文件等。它在 userscript 中通过 GM_xmlhttpRequest 发起请求,并模拟 fetch 风格的响应对象(提供 text(), json(), arrayBuffer() 方法)。


引入 / 安装(Tampermonkey 示例)

两种常见方式:

  1. 把类放到同一脚本中(直接定义 class)——你已有的做法。
  2. 把类放外部,并用 @require 引入(推荐复用):
// @grant       GM_xmlhttpRequest
// @connect     *
// @require     https://update.greasyfork.org/scripts/554239/1686624/WebDAVClient.js?v=1.0.0

注意:如果 WebDAVClient 使用 GM_xmlhttpRequest,主 userscript 必须声明 @grant GM_xmlhttpRequest,否则外部脚本无法访问该 API。 如果想在页面 console 或页面脚本访问该类,需要在外部库末尾 globalThis.WebDAVClient = WebDAVClient;(否则类仅在 userscript 沙箱中可见)。


快速开始(实例化与基本用法)

// 假设 WebDAVClient 已可用(通过 @require 或内联定义)
const client = new WebDAVClient({
  url: 'https://jike.teracloud.jp/dav/',
  username: 'wilsons',
  password: 'your-password',
  savePath: '/cursor-chat-history', // 可选:仅作记录/业务用途
});

// 列出一级目录(默认)
const list = await client.getDirectoryContents('/cursor-chat-history');
// 列出包括子目录(递归)
const listAll = await client.getDirectoryContents('/cursor-chat-history', { recursive: true });

// 读取文本文件
const txt = await client.getFileContents('/cursor-chat-history/hello.html', { format: 'text' });

// 上传(PUT)文件(覆盖)
await client.putFileContents('/cursor-chat-history/hello.html', 'hello world', { overwrite: true });

// 创建目录(递归)
await client.createDirectory('/cursor-chat-history/sub/dir', { recursive: true });

// 删除
await client.deleteFile('/cursor-chat-history/old.txt');

// 移动 / 复制
await client.moveFile('/from/path.txt', '/to/path.txt', { overwrite: true });
await client.copyFile('/from/path.txt', '/to/copy.txt', { overwrite: false });

API 参考(方法与行为)

所有方法都是 async,遇到 HTTP 错误或网络异常会抛异常(throw)。调用时请 try/catch

构造函数

new WebDAVClient({ url, username, password, savePath? })
  • url(必):WebDAV 根 URL,示例:https://server.example/dav/。内部会去掉尾部 / 以便拼接。
  • username, password(必):用于构造 Basic Auth。
  • savePath(可选):仅为业务字段,不影响客户端功能。

_request(method, path, options)

内部方法,包装 GM_xmlhttpRequest,返回一个模拟 fetch 响应对象(含 ok, status, statusText, text(), json(), arrayBuffer())。通常无需直接调用。

exists(path)

async exists(path) -> boolean 使用 HEAD 请求判断资源是否存在,无法连通或出错返回 false(并在控制台报错)。

createDirectory(path, options = { recursive: true })

创建目录;当 recursive: true 时会逐层 MKCOL。如果目录已存在且服务器返回 405(Method Not Allowed)会视为成功(因为 MKCOL 在已存在时常返回 405)。

getDirectoryContents(path, options = { recursive: false })

async getDirectoryContents(path, { recursive }) -> Array<{ filename, path, type }>

  • 默认只列一级(Depth: 1)。
  • recursive: true,函数会对每个子目录递归调用自身并返回扁平数组(目录条目会保留 type: 'directory')。
  • 返回项结构:

    • filename:文件名(已 decodeURIComponent)
    • path:原始 href 字符串(服务器返回)
    • type'file' | 'directory'
  • 库会默认过滤掉 macOS AppleDouble 文件(以 ._ 开头)和 .DS_Store,若需要可修改过滤规则。

getFileContents(path, options = { format: 'text' })

读取文件。format 支持:'text'(默认),'binary'(返回 ArrayBuffer),'json'(返回解析后的对象)。请求二进制请用 format: 'binary'(会设置 responseType: 'arraybuffer')。

putFileContents(path, content, options = { overwrite: true })

上传文件(PUT)。

  • content 可为字符串或二进制(若为二进制,需自己处理 Content-Type)。
  • options.overwrite === false 时,只在文件不存在时写入;否则抛出错误。
  • options.contentType 可指定 Content-Type

deleteFile(path)

删除文件 / 目录(由服务器实现行为决定)。

moveFile(fromPath, toPath, options = { overwrite: false })

MOVE,会设置 Destination 为完整 URL(库会调用 _getFullUrl(toPath)),OverwriteT/F

copyFile(fromPath, toPath, options = { overwrite: false })

COPY 操作,参数与 moveFile 相同。


常见使用场景示例(更完整)

userscript 头部示例(@require 引入)

// ==UserScript==
// @name         my-webdav-script
// @match        *://*/*
// @grant        GM_xmlhttpRequest
// @connect      *
// @require      https://update.greasyfork.org/scripts/554239/1686624/WebDAVClient.js?v=1.0.0
// ==/UserScript==

实际操作示例(含错误处理)

(async () => {
  try {
    const client = new WebDAVClient({
      url: 'https://jike.teracloud.jp/dav/',
      username: 'wilsons',
      password: await promptPassword() // 不要把密码硬编码
    });

    // 列出并打印一级文件
    const list = await client.getDirectoryContents('/cursor-chat-history');
    console.log('list:', list);

    // 递归列出全部
    const all = await client.getDirectoryContents('/cursor-chat-history', { recursive: true });
    console.log('all files (flat):', all);

    // 读文件
    const text = await client.getFileContents('/cursor-chat-history/hello.html');
    console.log('hello:', text);

    // 写文件
    await client.putFileContents('/cursor-chat-history/new.txt', 'hello from script', { overwrite: true });
    console.log('uploaded');

  } catch (err) {
    console.error('WebDAV 操作出错:', err);
  }
})();

排查与注意事项

1. Tampermonkey 权限 / 黑名单问题

  • 必须在脚本头加上 @grant GM_xmlhttpRequest 与合适的 @connect(或 @connect * 用于调试)。
  • 若你看到 status: 0 且错误 URL is blacklisted

    • 检查 Tampermonkey 仪表盘脚本设置的 XHR 黑名单/白名单;
    • 如果首次弹窗被拒绝或被记住拒绝,需在 Tampermonkey 设置中清除或重置 XHR 权限;
    • 也检查浏览器或其它扩展(uBlock/NoScript)是否阻止了请求。

2. 路径与 href 格式

  • 服务器返回 <D:href> 可能是绝对路径(/dav/...)或完整 URL;库会用 new URL(href, baseUrl) 进行规范化。
  • 注意 getDirectoryContents 默认跳过代表目录自身的 <href> 条目(即 /dav/dir/),所以不会把父目录重复列出。

3. macOS 产生的 ._* 文件

  • 这些是 AppleDouble(资源叉)文件,会出现在目录中。库默认过滤 ._*.DS_Store。如果你想包含这些,请修改过滤逻辑(getDirectoryContents 返回处)。

4. 递归与性能

  • 递归会对每个子目录额外发起一次 PROPFIND(Depth: 1)。大量文件或深目录会产生许多 HTTP 请求。若服务器允许 Depth: infinity,可考虑一次性请求(需要修改库;兼容性/权限问题多)。
  • 若需要高性能同步,考虑服务器端支持或分页、增量 sync。

5. 安全提示

  • 不要把明文密码硬编码发布到公开仓库或脚本头。可在运行时 prompt() 用户输入或使用受控存储(注意安全)。
  • 若将类暴露到 windowglobalThis.WebDAVClient = WebDAVClient),页面脚本与其他扩展可访问该构造函数,避免把敏感实例或凭证也放到全局。

常见问题(FAQ)

  • Q:为什么我看到 .DS_Store._xxx A:这是 macOS 文件系统的元数据或资源叉文件。库默认会过滤掉;若你想看到,修改过滤规则。

  • Q:getDirectoryContents 可以返回嵌套树结构吗? A:当前实现返回扁平数组(目录与文件在同一数组中,type 字段标识目录)。如果你需要嵌套树(每个目录有 children),可以在 getDirectoryContents 内部修改实现。我可以帮你改成嵌套结构(只需修改该函数)。

  • Q:怎么在页面控制台使用 WebDAVClient A:确保外部库在末尾做了 globalThis.WebDAVClient = WebDAVClient;。并且脚本要运行在能访问该全局的上下文(注意 @grant 会导致脚本运行在沙箱,需显式挂到 window)。

  • Q:服务器返回非标准 XML / 命名空间不同怎么办? A:库已做命名空间无关查找(getElementsByTagNameNS('*', ...)),能处理常见 D: / lp1: 前缀。如果遇到极端差异,请把 PROPFIND 响应贴上来,我会给出解析调整。


结语 / 推荐实践

  • 对于 userscript:尽量把 WebDAVClient 放在外部并用 @require 引入(便于复用与维护),并在主脚本中不要硬编码密码。
  • 在大目录或同步场景下,优先考虑服务器端支持更高效的 Depth: infinity 或专用同步接口。
  • 若你希望我把 getDirectoryContents 改为返回嵌套树(children),或把库改成支持 Depth: infinity 的一次性采集、或改进对二进制上传/下载的示例,我只修改最小必要代码并把完整代码输出给你(并标注修改位置)。