吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1196|回复: 18
上一主题 下一主题
收起左侧

[其他转载] 一款极简的网址导航源码 免服务器部署在cloudflare上

[复制链接]
跳转到指定楼层
楼主
pxhzai 发表于 2026-8-31 08:45 回帖奖励
本帖最后由 pxhzai 于 2026-8-31 08:53 编辑

在原版上在增加了 数据云端同步   Favicon第三方图标源

仓库地址
https://github.com/pxhzaii/NavSync

demo  
https://d.5as.cn/

部分代码/云端同步
[JavaScript] 纯文本查看 复制代码
// functions/api/[[path]].ts
// 云端同步 API — 基于 GitHub Gist + Cloudflare Pages Functions
//
// 端点:
//   POST /api/connect   连接(验证 Token + 检测 Gist,自动创建)
//   POST /api/upload    上传配置到 Gist
//   POST /api/download   从 Gist 拉取配置
//   POST /api/disconnect 断开(清空 Token)
//
// 安全:口令保护 + 暴力破解防护(5 次错误锁定 15 分钟)

import type { Env } from '../_shared'
import {
  checkPassword,
  fetchWithTimeout,
  gistHeaders,
  handleError,
  jsonResponse,
  readBody,
  GIST_API_URL,
  GIST_FILE,
} from '../_shared'

interface ConnectBody { token: string }
interface DataBody { data: string }

export const onRequestPost: PagesFunction<Env> = async (context) => {
  const { request, env } = context
  const url = new URL(request.url)
  const path = url.pathname.replace(/^\/api\/?/, '').toLowerCase()

  // 口令校验(未设置口令时跳过)
  const authError = checkPassword(request, env)
  if (authError) return authError

  try {
    switch (path) {
      case 'connect': return await handleConnect(request, env)
      case 'upload': return await handleUpload(request, env)
      case 'download': return await handleDownload(request, env)
      case 'disconnect': return jsonResponse({ success: true })
      default: return jsonResponse({ error: '未知端点' }, 404)
    }
  }
  catch (err: any) {
    return handleError(err)
  }
}

/** 连接:验证 Token + 检测/创建 Gist */
async function handleConnect(request: Request, env: Env): Promise<Response> {
  const { token } = await readBody<ConnectBody>(request)
  if (!token)
    return jsonResponse({ error: 'Token 不能为空' }, 400)

  const headers = gistHeaders(token)

  // 查询用户所有 Gists,找是否已有 navsync-config.json
  const resp = await fetchWithTimeout(GIST_API_URL, { headers })
  if (!resp.ok) {
    const msg = resp.status === 401 ? 'Token 无效' : `GitHub API ${resp.status}`
    return jsonResponse({ error: msg }, 400)
  }

  const gists = await resp.json()
  const existing = gists.find((g: any) =>
    g.files && g.files[GIST_FILE] !== undefined,
  )

  let gistId = existing?.id
  if (!gistId) {
    // 自动创建空 Gist
    const createResp = await fetchWithTimeout(GIST_API_URL, {
      method: 'POST',
      headers,
      body: JSON.stringify({
        description: 'NavSync Cloud Sync',
        public: false,
        files: { [GIST_FILE]: { content: '{}' } },
      }),
    })
    if (!createResp.ok)
      return jsonResponse({ error: '创建 Gist 失败' }, 500)
    const created = await createResp.json()
    gistId = created.id
  }

  return jsonResponse({ success: true, gistId })
}

/** 上传:将配置写入 Gist */
async function handleUpload(request: Request, env: Env): Promise<Response> {
  const { token } = await readBody<{ token: string }>(request)
  const { data } = await readBody<DataBody>(request)
  if (!token || !data)
    return jsonResponse({ error: '参数缺失' }, 400)

  const headers = gistHeaders(token)
  const resp = await fetchWithTimeout(`${GIST_API_URL}`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      files: { [GIST_FILE]: { content: data } },
    }),
  })

  if (!resp.ok)
    return jsonResponse({ error: '上传失败' }, 500)

  return jsonResponse({ success: true })
}

/** 下载:从 Gist 读取配置 */
async function handleDownload(request: Request, env: Env): Promise<Response> {
  const { token } = await readBody<{ token: string }>(request)
  if (!token)
    return jsonResponse({ error: 'Token 不能为空' }, 400)

  const headers = gistHeaders(token)
  const resp = await fetchWithTimeout(GIST_API_URL, { headers })

  if (!resp.ok)
    return jsonResponse({ error: '下载失败' }, 500)

  const gists = await resp.json()
  const target = gists.find((g: any) =>
    g.files && g.files[GIST_FILE] !== undefined,
  )

  if (!target)
    return jsonResponse({ error: '未找到同步数据' }, 404)

  const fileResp = await fetchWithTimeout(
    `${GIST_API_URL}/${target.id}`,
    { headers },
  )
  const gist = await fileResp.json()
  const content = gist.files?.[GIST_FILE]?.content || '{}'

  return jsonResponse({ success: true, data: content })
}

免费评分

参与人数 4吾爱币 +2 热心值 +3 收起 理由
yang0828 + 1 热心回复!
wzdf + 1 我很赞同!
cajs0001 + 1 谢谢@Thanks!
念夕空 + 1 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

来自 2#
 楼主| pxhzai 发表于 2026-8-31 09:24 |楼主
本帖最后由 pxhzai 于 2026-8-31 10:13 编辑
quakewg 发表于 2026-8-31 09:05
感谢大佬!请问能不能自动把edge保存的书签,同步设定进网页,这样在公用电脑就可以通过网址访问自己的书签 ...

导出书签-转换导航格式-导入浏览器-上传云端

可视化 调整 分类/分组
书签里不在文件夹内的链接,被放在默认分组。一个文件夹A内有多个文件夹,被提取分配到一个文件夹A


https://pxhzai.lanzoub.com/b03cbbb8fi 密码:8hed
推荐
quakewg 发表于 2026-8-31 09:05
感谢大佬!请问能不能自动把edge保存的书签,同步设定进网页,这样在公用电脑就可以通过网址访问自己的书签了
5#
念夕空 发表于 2026-8-31 08:54
学到了。哈哈,有空就搞一个, 把我所有书签都搞进去。
6#
q1wv 发表于 2026-8-31 09:01
很漂亮的代码啊。本来以为要做成每次更新写一个新的静态页面,这个挺快,不用优化。
7#
fuvenusck 发表于 2026-8-31 09:08
谢谢分享,很使用的网址导航源码
8#
飘浮 发表于 2026-8-31 09:16
真不错。。要是有个PHP就好了。。
9#
 楼主| pxhzai 发表于 2026-8-31 09:29 |楼主
飘浮 发表于 2026-8-31 09:16
真不错。。要是有个PHP就好了。。

php可以去使用六零导航 也是免费的  
10#
念夕空 发表于 2026-8-31 09:48
quakewg 发表于 2026-8-31 09:05
感谢大佬!请问能不能自动把edge保存的书签,同步设定进网页,这样在公用电脑就可以通过网址访问自己的书签 ...

我也是这么想的,正在用workbuddy准备实现这个功能,哈哈哈
11#
 楼主| pxhzai 发表于 2026-8-31 09:49 |楼主
念夕空 发表于 2026-8-31 09:48
我也是这么想的,正在用workbuddy准备实现这个功能,哈哈哈

已经有了
https://www.52pojie.cn/forum.php ... 03&pid=55812759
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-9-1 00:10

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表