用Cloudflare worker自建短链接服务

513次阅读
37 条评论

共计 6894 个字符,预计需要花费 18 分钟才能阅读完成。

题外话:CloudFlare 的毛都快被薅秃了吧!
我的短链接服务网址:

短链接

短链接又称短网址、短码,意思就是形式上比较短的网址。短链接服务,可以通过将一个普通的冗长的网址缩短生成一个新的较短的网址,便于分享传播。

短链接主要应用场景如下:

  • 短信发送
    短信里用短链接,可以极大减少字符,现在很多营销短信都是用的短网址。

  • 社群推广
    很多社区或社交网站,会屏蔽长链接。微博字数限制,公众号关键字链接限制等,短网址可以缩短字符,规避掉这些限制。

  • 微信防屏蔽
    微信里有各种屏蔽,用短链接可以避免暴露原有地址关键字,规避屏蔽。

  • 活码
    短网址是固定的,可以通过修改原链接达到变更地址的作用,此时不用去修改固定的短网址,短网址就相当于一个中间层。主要用于替换更换链接成本较高的地方,比如生成好的二维码等。

PS:短链接服务一定要用大厂,一般不至于跑路,稳定性有所保证。
GitHub,你看看你?git.io 等我想用时候就跑路了!

自建短链接平台

这里利用 cloudflare workers 提供的服务,免费版本每日 100000 次请求,对个人使用而言完全足够。

脚本配置基于 GitHub 开源项目AoEiuV020/Url-Shorten-Worker

你需要准备的:

  • 一个 cloudflare 帐号
  • 一个自己的域名,越短越好,并托管到 cloudflare

实施步骤:
1,登陆你的 cloudflare 帐号,在 Workers KV 中创建一个命名空间,名称随意(尽量短)
用 Cloudflare worker 自建短链接服务

2,Workers 创建新服务
用 Cloudflare worker 自建短链接服务

3,服务名称随意,启动器选择 http 路由器。
用 Cloudflare worker 自建短链接服务

4,进入 Workers 服务,设置 =》变量 =》KV 命名空间绑定,变量名称大写 LINKS,值就是那个命名空间名;环境变量里再添加系列变量。变量说明如下:
调整超时设置
演示模式生成的短链接超时无法访问,
白名单或者密码正确情况超时设置无效,
修改脚本开头的变量 SHORTEN_TIMEOUT, 单位毫秒,0 表示不设置超时

调整白名单 白名单中的域名设置短链接无视超时,
修改脚本开头的变量 WHITE_LIST, 是个 json 数组,写顶级域名就可以,自动通过顶级域名和所有二级域名

关闭演示模式 只有演示模式开启才允许访客无密码添加非白名单地址,超时短链接会失效,
修改脚本开头的变量 DEMO_MODE,为 true 开启演示,为 false 无密码且非白名单请求不受理

自动删除演示记录 针对演示模式开启情况下的超时失效的短链接记录是否自动删除,
修改脚本开头的变量 REMOVE_COMPLETELY,为 true 自动删除超时的演示短链接记录,否则仅是标记过期,以便在后台查询历史记录

修改密码 网页有个隐藏输入框可以输入密码,
密码正确情况无视白名单和超时设置,且支持自定义短链接,
修改脚本开头的变量 PASSWORD,这个私密信息比较建议直接在环境变量里配置

修改短链长度 短链长度就是随机生成的 key 也就是短链接的 path 部分的长度,
长度不够时容易出现重复,遇到重复时会自动延长,
修改脚本开头的变量 DEFAULT_LEN

注意:key 均为对应大写
用 Cloudflare worker 自建短链接服务

用 Cloudflare worker 自建短链接服务

用 Cloudflare worker 自建短链接服务

5, 回到【资源】,快速编辑,复制项目中的 index.js 的代码,即以下代码内容,保存并编译。
用 Cloudflare worker 自建短链接服务

用 Cloudflare worker 自建短链接服务

//index.js 源代码


// 项目名,决定 html 从哪个项目获取,const github_repo = typeof(GITHUB_REPO)!="undefined" ? GITHUB_REPO
    : 'charlie-king/Url-Shorten-Worker'
// 项目版本,cdn 会有缓存,所以有更新时需要指定版本,const github_version = typeof(GITHUB_VERSION)!="undefined" ? GITHUB_VERSION
    : '@main'
// 密码,密码正确情况无视白名单和超时设置,且支持自定义短链接,const password = typeof(PASSWORD)!="undefined" ? PASSWORD
    : 'AoEiuV020 yes'
// 短链超时,单位毫秒,支持整数乘法,0 表示不设置超时,const shorten_timeout = typeof(SHORTEN_TIMEOUT)!="undefined" ? SHORTEN_TIMEOUT.split("*").reduce((a,b)=>parseInt(a)*parseInt(b),1)
    : (1000 * 60 * 10)
// 默认短链 key 的长度,遇到重复时会自动延长,const default_len = typeof(DEFAULT_LEN)!="undefined" ? parseInt(DEFAULT_LEN)
    : 6
// 为 true 开启演示,否则无密码且非白名单请求不受理,是则允许访客试用,超时后失效,const demo_mode = typeof(DEMO_MODE)!="undefined" ? DEMO_MODE === 'true'
    : true
// 为 true 自动删除超时的演示短链接记录,否则仅是标记过期,以便在后台查询历史记录,const remove_completely = typeof(REMOVE_COMPLETELY)!="undefined" ? REMOVE_COMPLETELY === 'true'
    : true
// 白名单中的域名无视超时,json 数组格式,写顶级域名就可以,自动通过顶级域名和所有二级域名,const white_list = JSON.parse(typeof(WHITE_LIST)!="undefined" ? WHITE_LIST
    : `[
"aoeiuv020.com",
"aoeiuv020.cn",
"aoeiuv020.cc",
"020.name"
    ]`)
// 演示模式开启时网页上展示这段禁止滥用提示,并不需要明确表示什么时候失效,const demo_notice = typeof(DEMO_NOTICE)!="undefined" ? DEMO_NOTICE
    : ` 注意:为防止示例服务被人滥用,故所有由 demo 网站生成的链接随时可能失效,如需长期使用请自行搭建。`
//console.log(`${github_repo}, ``{github_version}, ``{password}, ``{shorten_timeout}, ``{demo_mode}, ``{white_list}, ``{demo_notice}`)
const html404 = `<!DOCTYPE html>
<body>
  <h1>404 Not Found.</h1>
  <p>The url you visit is not found.</p>
</body>`
async function randomString(len) {
    let $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';    /**** 默认去掉了容易混淆的字符 oOLl,9gq,Vv,Uu,I1****/
    let maxPos = $chars.length;
  let result = '';
  for (i = 0; i < len; i++) {result += $chars.charAt(Math.floor(Math.random() * maxPos));
  }
  return result;
}
async function checkURL(url){
    let str=url;
    let Expression=/^http(s)?:\/\/(.*@)?([\w-]+\.)*[\w-]+([_\-.,~!*:#()\w\/?%&=]*)?$/;
    let objExp=new RegExp(Expression);
    if(objExp.test(str)==true){if (str[0] == 'h')
        return true;
      else
        return false;
    }else{return false;}
}

// 检查域名是否在白名单中,参数只包含域名部分,async function checkWhite(host){return white_list.some((h) => host == h || host.endsWith('.'+h))
}
async function md5(message) {const msgUint8 = new TextEncoder().encode(message) // encode as (utf-8) Uint8Array
  const hashBuffer = await crypto.subtle.digest('MD5', msgUint8) // hash the message
  const hashArray = Array.from(new Uint8Array(hashBuffer)) // convert buffer to byte array
  const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('') // convert bytes to hex string
  return hashHex
}
async function checkHash(url, hash) {if (!hash) {return false}
    return (await md5(url+password)) == hash
}
async function save_url(url, key, admin, len) {
  len = len || default_len;
    // 密码正确且指定了 key 的情况直接覆盖旧值,const override = admin && key
    if (!override) {
        // 密码不正确情况无视指定 key,
        key = await randomString(len)
    }
    const is_exists = await load_url(key)
    console.log("key exists " + key + " " + is_exists)
    if (override || !is_exists) {
        var mode = 3
        if (admin) {mode = 0}
       let value = `${mode};``{Date.now()};``{url}`
        if (remove_completely && mode != 0 && !await checkWhite(new URL(url).host)) {
          // 利用 expirationTtl 实现过期记录自动删除,低于 60 秒会报错,let ttl = Math.max(60, shorten_timeout / 1000)
          console.log("key auto remove: " + key + ", " + ttl + "s")
          return await LINKS.put(key, value, {expirationTtl: ttl}),key
        } else {return await LINKS.put(key, value),key
        }
    } else {return await save_url(url, key, admin, len + 1)
    }
}
async function load_url(key) {const value = await LINKS.get(key)
    if (!value) {return null}
    const list = value.split(';')
    console.log("value split " + list)
    var url
    if (list.length == 1) {
        // 老数据暂且正常跳转,url = list[0]
    } else {url = list[2]
        const mode = parseInt(list[0])
        const create_time = parseInt(list[1])
        if (mode != 0 && shorten_timeout > 0
            && Date.now() - create_time > shorten_timeout) {const host = new URL(url).host
            if (await checkWhite(host)) {console.log('white list')
            } else {
                // 超时和找不到做同样的处理,console.log("shorten timeout")
                return null
            }
        }
    }
    return url
}
async function handleRequest(request) {console.log(request)
  if (request.method === "POST") {let req=await request.json()
    console.log("url " + req["url"])
    let admin = await checkHash(req["url"], req["hash"])
    console.log("admin " + admin)
    if(!await checkURL(req["url"]) || (!admin && !demo_mode && !await checkWhite(new URL(req["url"]).host))){
    // 非演示模式下,非白名单地址当成地址不合法处理,return new Response(`{"status":500,"key":": Error: Url illegal."}`, {
      headers: {
      "content-type": "text/html;charset=UTF-8",
      "Access-Control-Allow-Origin":"*",
      "Access-Control-Allow-Methods": "POST",
      },
    })}
    let stat,random_key=await save_url(req["url"], req["key"], admin)
    console.log("stat " + stat)
    if (typeof(stat) == "undefined"){return new Response(`{"status":200,"key":"/`+random_key+`"}`, {
      headers: {
      "content-type": "text/html;charset=UTF-8",
      "Access-Control-Allow-Origin":"*",
      "Access-Control-Allow-Methods": "POST",
      },
    })
    }else{return new Response(`{"status":200,"key":": Error:Reach the KV write limitation."}`, {
      headers: {
      "content-type": "text/html;charset=UTF-8",
      "Access-Control-Allow-Origin":"*",
      "Access-Control-Allow-Methods": "POST",
      },
    })}
  }else if(request.method === "OPTIONS"){  
      return new Response(``, {
      headers: {
      "content-type": "text/html;charset=UTF-8",
      "Access-Control-Allow-Origin":"*",
      "Access-Control-Allow-Methods": "POST",
      },
    })
  }
  const requestURL = new URL(request.url)
  const path = requestURL.pathname.split("/")[1]
  console.log(path)
  if(!path){const html= await fetch(`https://cdn.jsdelivr.net/gh/${github_repo}${github_version}/index.html`)
    const text = (await html.text())
        .replaceAll("###GITHUB_REPO###", github_repo)
        .replaceAll("###GITHUB_VERSION###", github_version)
        .replaceAll("###DEMO_NOTICE###", demo_notice)
    return new Response(text, {
    headers: {"content-type": "text/html;charset=UTF-8",},
  })
  }
  const url = await load_url(path)
  if (!url) {
    // 找不到或者超时直接 404,
    console.log('not found')
    return new Response(html404, {
      headers: {"content-type": "text/html;charset=UTF-8",},
      status: 404
    })
  }
  return Response.redirect(url, 302)
}
addEventListener("fetch", async event => {event.respondWith(handleRequest(event.request))
})

6, 最后一步,添加自定义域名,域名需先托管到 cloudflare 解析,此时你就可以通过这个域名访问并生成短链接了。
用 Cloudflare worker 自建短链接服务

用 Cloudflare worker 自建短链接服务

正文完
 
lucky
版权声明:本站原创文章,由 lucky 2023-02-14发表,共计6894字。
转载说明:转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(37 条评论)
2024-07-14 04:29:06 回复

Your article helped me a lot, is there any more related content? Thanks!

 Windows  Edge  美国加利福尼亚旧金山
2024-08-02 06:59:47 回复

Your point of view caught my eye and was very interesting. Thanks. I have a question for you.

 Windows  Edge  拉脱维亚Riga
2024-08-05 04:40:10 回复

lasuna buy online – buy diarex pill purchase himcolin without prescription

 Windows  Chrome  美国加利福尼亚旧金山
2024-08-18 17:56:08 回复

besifloxacin for sale online – how to buy sildamax sildamax tablets

 Windows  Chrome  美国加利福尼亚旧金山
2024-08-21 12:43:00 回复

neurontin 100mg cheap – buy sulfasalazine 500 mg buy azulfidine 500 mg generic

 Windows  Chrome  俄罗斯列宁格勒圣彼得堡
2024-08-23 14:10:22 回复

probenecid 500mg ca – order probenecid pills buy tegretol 400mg pills

 Windows  Chrome  挪威Oslo
2024-08-27 05:00:42 回复

brand celebrex 200mg – indocin 50mg price buy indomethacin for sale

 Windows  Chrome  俄罗斯列宁格勒圣彼得堡
2024-08-27 23:45:10 回复

buy cheap generic colospa – order pletal 100 mg oral pletal 100mg

 Windows  Chrome  美国加利福尼亚旧金山
2024-09-01 01:05:52 回复

buy voltaren 100mg without prescription – voltaren 100mg cheap where to buy aspirin without a prescription

 Windows  Chrome  巴西圣保罗圣保罗
2024-09-05 09:45:14 回复

purchase rumalaya generic – buy elavil generic order amitriptyline 50mg online cheap

 Windows  Chrome  俄罗斯列宁格勒圣彼得堡
2024-09-08 22:19:46 回复

generic pyridostigmine – order mestinon 60mg online azathioprine 25mg cheap

 Windows  Chrome  美国加利福尼亚旧金山
2024-09-12 09:14:06 回复

buy voveran paypal – imdur 20mg cost how to get nimodipine without a prescription

 Windows  Chrome  美国加利福尼亚旧金山
2024-09-14 19:00:45 回复

buy baclofen 10mg generic – purchase ozobax pills piroxicam generic

 Windows  Chrome  巴西圣保罗圣保罗
2024-09-18 08:33:32 回复

order meloxicam 15mg for sale – order toradol 10mg ketorolac uk

 Windows  Chrome  俄罗斯列宁格勒圣彼得堡
2024-09-20 05:53:08 回复

cyproheptadine order – cyproheptadine for sale online buy tizanidine pills

 Windows  Chrome  美国加利福尼亚旧金山
2024-09-24 04:25:07 回复

trihexyphenidyl buy online – order diclofenac gel online cheap voltaren gel online order

 Windows  Chrome  俄罗斯列宁格勒圣彼得堡
2024-09-26 08:12:49 回复

omnicef 300mg sale – buy generic clindamycin for sale

 Windows  Chrome  美国新泽西
2024-09-29 14:30:46 回复

order isotretinoin sale – order avlosulfon 100 mg generic buy deltasone 40mg for sale

 Windows  Chrome  俄罗斯列宁格勒圣彼得堡
2024-10-02 17:43:49 回复

buy prednisone paypal – permethrin oral permethrin buy online

 Windows  Chrome  美国加利福尼亚旧金山
2024-10-04 23:22:51 回复

order permethrin generic – benzac without prescription retin online order

 Windows  Chrome  巴西圣保罗圣保罗
2024-10-08 08:19:31 回复

betamethasone us – buy adapalene cream for sale purchase monobenzone online

 Windows  Chrome  美国加利福尼亚旧金山
2024-10-09 20:10:43 回复

buy flagyl online – brand flagyl cenforce 100mg price

 Windows  Chrome  美国加利福尼亚旧金山
2024-10-14 01:17:29 回复

buy augmentin 625mg – order synthroid 75mcg synthroid cost

 Windows  Chrome  巴西圣保罗圣保罗
2024-10-16 23:54:07 回复

buy cleocin generic – cleocin 150mg sale indocin brand

 Windows  Chrome  美国加利福尼亚旧金山
2024-10-18 23:27:54 回复

cozaar buy online – purchase hyzaar pills cost keflex 500mg

 Windows  Chrome  美国加利福尼亚旧金山
2024-10-21 19:03:55 回复

order crotamiton online – cheap bactroban ointment aczone online

 Windows  Chrome  美国加利福尼亚旧金山
2024-10-24 09:50:44 回复

purchase provigil online – promethazine tablet order melatonin 3 mg pills

 Windows  Chrome  美国加利福尼亚旧金山
2024-10-26 10:47:37 回复

buy bupropion 150 mg pill – xenical 60mg oral buy shuddha guggulu no prescription

 Windows  Chrome  美国加利福尼亚旧金山
2024-10-30 10:09:26 回复

buy capecitabine 500mg for sale – buy naprosyn 500mg sale order danocrine generic

 Windows  Chrome  英国伦敦伦敦
2024-10-31 04:10:15 回复

prometrium drug – clomiphene oral buy generic fertomid over the counter

 Windows  Chrome  美国加利福尼亚旧金山
2024-11-04 20:36:14 回复

fosamax 35mg sale – buy pilex pills order provera 10mg generic

 Windows  Chrome  美国加利福尼亚旧金山
2024-11-05 09:47:07 回复

norethindrone online – cost norethindrone 5mg yasmin over the counter

 Windows  Chrome  美国加利福尼亚旧金山
2024-11-10 02:01:54 回复

I don’t think the title of your article matches the content lol. Just kidding, mainly because I had some doubts after reading the article.

 Windows  Edge  美国加利福尼亚旧金山
2024-11-11 11:05:45 回复

dostinex 0.25mg sale – alesse online buy alesse for sale

 Windows  Chrome  美国加利福尼亚旧金山
2024-11-12 02:05:16 回复

estrace 2mg over the counter – femara 2.5mg oral arimidex 1mg uk

 Windows  Chrome  英国伦敦伦敦
2024-11-17 17:01:55 回复

г‚·гѓ«гѓ‡гѓЉгѓ•г‚Јгѓ« гЃЉгЃ™гЃ™г‚Ѓ – バイアグラ и–¬е±ЂгЃ§иІ·гЃ€г‚‹ г‚·г‚ўгѓЄг‚№ еЂ¤ж®µ

 Windows  Chrome  英国伦敦伦敦
2024-11-18 22:33:41 回复

гѓ—гѓ¬гѓ‰гѓ‹гѓі гЃ©гЃ“гЃ§иІ·гЃ€г‚‹ – プレドニンジェネリック йЂљиІ© г‚ёг‚№гѓ­гѓћгѓѓг‚Ї еЂ¤ж®µ

 Windows  Chrome  英国伦敦伦敦