前言

最近搭建了一个兰空图床,我想挂载一个储存做为我的长期存储图片的图床,想起了之前白嫖的InfiniCLOUD,我的免费额度已经到四十多G了。所以顺便写了一个反代webdav的代码,在1panel一键部署。


环境准备

所需工具和环境:

开发环境:

  • 操作系统:Debian
  • WebDAV 服务:InfiniCLOUD 免费账户

功能实现

我希望实现以下目标:

  1. 移除直接访问 WebDAV 时的密码验证步骤。
  2. 根据用户访问路径动态代理文件或目录。
  3. 通过服务器自动完成 Basic Auth 验证。

核心代码解析

以下是代码的主要逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
const express = require('express');
const axios = require('axios');
const path = require('path');
const mime = require('mime-types');
const app = express();

// WebDAV 配置
const WEBDAV_URL = 'webdav地址';
const WEBDAV_USERNAME = '账号';
const WEBDAV_PASSWORD = '密码';

// 创建 Basic Auth 头
const basicAuth = Buffer.from(`${WEBDAV_USERNAME}:${WEBDAV_PASSWORD}`).toString('base64');

app.get('*', async (req, res) => {
try {
let requestPath = req.path;

// 构造完整的 WebDAV 请求 URL
const fullUrl = WEBDAV_URL + (requestPath.startsWith('/') ? requestPath.substring(1) : requestPath);

// 使用 axios 请求 WebDAV 服务器
const response = await axios({
method: 'GET',
url: fullUrl,
headers: {
'Authorization': `Basic ${basicAuth}`
},
responseType: 'stream'
});

// 根据文件后缀设置 Content-Type
const contentType = mime.lookup(path.extname(requestPath)) || 'application/octet-stream';
res.setHeader('Content-Type', contentType);
if (response.headers['content-length']) res.setHeader('Content-Length', response.headers['content-length']);
if (response.headers['last-modified']) res.setHeader('Last-Modified', response.headers['last-modified']);

// 将 WebDAV 响应数据传递给客户端
response.data.pipe(res);

} catch (error) {
console.error('Error:', error.message);
res.status(error.response?.status || 500).send({ error: '访问 WebDAV 资源失败' });
}
});

// 监听端口
const PORT = process.env.PORT || 3090;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});

package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"name": "webdav-proxy",
"version": "1.0.0",
"description": "A proxy server for WebDAV file access",
"main": "server.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js"
},
"keywords": [
"webdav",
"proxy",
"file-server"
],
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^1.6.2",
"express": "^4.18.2",
"mime-types": "^2.1.35"
},
"devDependencies": {
"nodemon": "^3.0.2"
},
"engines": {
"node": ">=14.0.0"
}
}

核心逻辑

  1. WebDAV 配置
    定义 WebDAV 服务的 URL 和账户认证信息,并利用 Base64 编码创建 Basic Auth 头。

  2. 动态路径映射
    根据用户访问的路径,动态构造完整的 WebDAV 请求 URL。

  3. 流式传输文件
    使用 axiosresponseType: 'stream' 参数将 WebDAV 响应直接传递给客户端,减少内存占用。

  4. 设置 MIME 类型
    通过 mime-types 库,根据文件后缀设置正确的 Content-Type,保证浏览器的文件渲染效果。


部署与运行

  1. 将两个文件导入服务器的一个文件夹:

随后在 网站-运行环境,选择创建运行环境,选择你存放的文件夹

最后部署即可。