IPFSCDN.js - 基于 Helia 的浏览器端 CDN

IPFSCDN.js - 基于 Helia 的浏览器端 CDN

一个纯 JavaScript 实现的浏览器端 CDN 系统,利用 IPFS/Helia 将访问者的浏览器变成内容分发节点。

核心概念

传统 CDN:用户从边缘节点下载内容 IPFSCDN:用户浏览器成为边缘节点,互相分享内容

传统模式:  用户 ← 服务器
IPFSCDN:   用户 ← 本地 IPFS 节点 ← 其他用户 / 服务器

功能特性

1. 自动图片拦截

  • 页面加载时自动拦截所有 <img> 标签
  • 防止图片直接从源服务器加载
  • 支持动态添加的图片(MutationObserver)

2. 本地 IPFS 存储

  • 将图片下载并存入浏览器中的 Helia 节点
  • 生成 CID(内容标识符)
  • 自动固定内容,防止被垃圾回收

3. 本地内容提供

  • 后续访问直接从本地节点获取图片
  • 使用 Blob URL 显示图片
  • 大幅降低源服务器负载

4. 图片状态标识 ⭐

每张图片右下角显示彩色圆点,直观展示当前状态:

颜色状态说明
🟢 绿色本地提供图片已从本地 IPFS 节点加载
🟡 黄色远程回退图片从原始服务器加载(下载失败或首次访问)
🔵 蓝色(闪烁)处理中正在下载并存储到 IPFS

5. 自动内容分发

  • 将 CID 广播到 IPFS 网络
  • 其他节点可以发现并获取这些内容
  • 定期重新广播,确保内容可发现性

6. 智能回退

  • 下载失败时自动回退到原始源
  • 支持重试机制
  • 错误处理和恢复

使用方法

基本使用

只需在 HTML 页面中添加一行代码:

<script type="module" src="ipfscdn.js"></script>

IPFSCDN 会自动:

  1. 初始化 Helia 节点
  2. 拦截页面所有图片
  3. 下载并存储到本地 IPFS
  4. 从本地提供图片
  5. 广播 CID 到网络
  6. 在图片右下角显示状态标识

完整示例

<!DOCTYPE html>
<html>
<head>
    <title>我的网站</title>
</head>
<body>
    <!-- 普通图片 -->
    <img src="https://example.com/image1.jpg" alt="图片1">
    <img src="https://example.com/image2.jpg" alt="图片2">
    
    <!-- 加载 IPFSCDN -->
    <script type="module" src="ipfscdn.js"></script>
</body>
</html>

工作原理

1. 图片拦截流程

// 1. 保存原始 src
img.dataset.ipfscdnOriginalSrc = absoluteSrc

// 2. 设置占位符(防止立即加载)
img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'

// 3. 添加处理中标识
addBadgeToImage(img, 'loading')

// 4. 异步处理
processImage(img)

2. 存储流程

// 1. 下载图片
const response = await fetch(url)
const blob = await response.blob()

// 2. 存储到 IPFS
const cid = await fs.addBytes(uint8Array)

// 3. 固定内容
await helia.pins.add(cid)

// 4. 保存映射关系
localStorage.setItem('ipfscdn_' + hash(url), JSON.stringify({cid, timestamp}))

// 5. 更新标识为本地状态
addBadgeToImage(img, 'local')

3. 提供流程

// 1. 从本地获取
for await (const chunk of fs.cat(cid)) {
    chunks.push(chunk)
}

// 2. 创建 Blob URL
const blob = new Blob(chunks)
const url = URL.createObjectURL(blob)

// 3. 设置图片源
img.src = url

// 4. 更新标识
addBadgeToImage(img, 'local')

4. 状态标识实现

// 创建 wrapper 容器
const wrapper = document.createElement('div')
wrapper.className = 'ipfscdn-wrapper'
wrapper.style.position = 'relative'

// 将图片放入 wrapper
img.parentNode.insertBefore(wrapper, img)
wrapper.appendChild(img)

// 添加状态标识
const badge = document.createElement('div')
badge.className = 'ipfscdn-badge local' // 或 'remote', 'loading'
badge.style.cssText = `
    position: absolute;
    bottom: 8px;
    right: 8px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    border: 2px solid white;
    z-index: 1000;
`
wrapper.appendChild(badge)

5. 分发流程

// 广播 CID 到 DHT
await helia.libp2p.contentRouting.provide(cid)

// 定期重新广播
setInterval(() => announceContent(), 60000)

配置选项

ipfscdn.js 中修改 CONFIG 对象:

const CONFIG = {
    // 引导节点列表
    BOOTSTRAP_NODES: [
        '/ip4/164.92.116.163/udp/4001/webrtc-direct/...',
        // ... 其他节点
    ],
    
    // 并发处理数
    CONCURRENT_LIMIT: 3,
    
    // 重试次数
    MAX_RETRIES: 3,
    
    // 超时时间(毫秒)
    TIMEOUT: 30000,
    
    // 是否自动分发
    AUTO_PROVIDE: true,
    
    // 调试模式
    DEBUG: true
}

技术栈

  • IPFS 实现: Helia (浏览器端 IPFS 节点)
  • 传输协议: WebRTC-direct, WebSockets
  • 存储: Memory Blockstore / localStorage (映射缓存)
  • 模块系统: ES Modules (通过 CDN 加载)

引导节点

默认配置了以下引导节点:

  1. 自定义节点(推荐)

`` /ip4/164.92.116.163/udp/4001/webrtc-direct/certhash/uEiB-LSkXRRznjYd7TGyssl9HjuwPrpduoQ-DKKVXIZK0jw/p2p/12D3KooWN57Fmw7NEAXiFa76TLH8JaJjUvTisfGu1ufjtjTt6Fg3 ``

  1. 公共引导节点

`` /dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN /dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa ``

状态面板

IPFSCDN 会在页面右下角显示实时状态面板:

  • 节点状态: Helia 节点连接状态
  • 总图片数: 页面中发现的图片总数
  • 本地缓存: 已存储到本地 IPFS 的图片数
  • 本地提供: 从本地节点提供的图片数
  • 远程回退: 从原始源加载的图片数

同时包含状态标识图例说明。

API 接口

IPFSCDN 暴露全局对象 window.ipfscdn,可用于调试:

// 查看统计
console.log(ipfscdn.stats)

// 手动触发内容广播
ipfscdn.announceContent()

// 查看缓存的 CID
console.log(ipfscdn.imageCache)

// 查看 Helia 节点
console.log(ipfscdn.helia)

// 为指定图片添加状态标识
ipfscdn.addBadgeToImage(imgElement, 'local')

浏览器兼容性

  • Chrome 90+
  • Firefox 88+
  • Edge 90+
  • Safari 14+

要求:

  • 支持 ES Modules
  • 支持 WebRTC
  • 必须在 HTTPS 或 localhost 环境下运行

部署说明

1. 静态托管

IPFSCDN 是纯前端项目,可部署到任何静态托管:

# GitHub Pages
# 直接推送代码,在仓库设置中启用 Pages

# Netlify
# 拖拽上传文件夹即可

# 自有服务器
# 将文件复制到 web 根目录

2. HTTPS 要求

WebRTC 必须在安全上下文中运行,部署时必须使用 HTTPS。

本地开发:

# 使用 mkcert 生成本地证书
npx serve -s . --ssl-cert cert.pem --ssl-key key.pem

性能优化

1. 并发控制

限制同时处理的图片数量,避免网络拥塞:

CONCURRENT_LIMIT: 3  // 同时处理 3 张图片

2. 缓存策略

  • 内存缓存:运行时快速访问
  • localStorage:持久化 CID 映射
  • IPFS 固定:防止内容被垃圾回收

3. 流式处理

大图片使用流式下载和存储,避免内存溢出:

for await (const chunk of fs.cat(cid)) {
    chunks.push(chunk)
}

注意事项

1. CORS 限制

图片源服务器必须允许跨域访问,否则无法下载。

解决方案:

  • 配置服务器 CORS 头
  • 使用同域图片
  • 使用图片代理服务

2. 存储空间

浏览器存储空间有限,大图片或大量图片可能超出限制。

建议:

  • 定期清理未固定内容
  • 监控存储使用情况
  • 提供手动清理选项

3. 隐私考虑

IPFSCDN 会将图片内容广播到公共网络,不适合敏感图片。

未来改进

  • [ ] 图片加密存储
  • [ ] Service Worker 离线支持
  • [ ] 图片压缩优化
  • [ ] 更多内容类型支持(CSS, JS, 字体)
  • [ ] 统计和监控面板
  • [ ] 多节点负载均衡

相关项目

  • Helia - IPFS 的 JavaScript 实现
  • HeliaShare - 基于 Helia 的文件分享应用

许可证

MIT License


让浏览器成为 CDN 节点,共建去中心化网络!

← 返回目录