目 录CONTENT

文章目录

无服务器 自建短链服务Url-Shorten-Worker - 完整的部署教程

XiaoWan💞
2022-10-20 / 0 评论 / 0 点赞 / 115 阅读 / 2,417 字 / 正在检测是否收录...

源码 GitHub: https://github.com/xyTom/Url-Shorten-Worker/

修改版源码 GitHub: https://github.com/crazypeace/Url-Shorten-Worker

申请Cloudflare账号,略。

创建一个KV

记住这个KV的名字,以 url为例

1

查看此KV

2

添加一个条目Entry

密钥key为password,值为一个随机字符串.

* password这个key是在脚本中要引用的,所以要设置这个。

随机字符串以 url为例

3

创建Worker服务

4

5

设置绑定KV

6

7

变量名称必须设置为 LINKS, KV的名字选刚刚创建的 url

LINKS 是在脚本中要引用的,所以要设置这个。换句话说,如果你使用别的脚本,可能这个变量名称就不是LINKS了。

编辑Worker的脚本

9

把原有的内容全部删掉,换成:https://github.com/xyTom/Url-Shorten-Worker/blob/main/index.js 的内容,保存并部署

修改版

代码链接

https://github.com/crazypeace/Url-Shorten-Worker/blob/main/index.js

在原版基础上的修改说明

直接访问域名返回404。在KV中设置一个entry,保存秘密path,只有访问这个path才显示使用页面。

https://zelikk.blogspot.com/2022/07/url-shorten-worker-hide-tutorial.html

支持自定义短链

https://zelikk.blogspot.com/2022/07/url-shorten-worker-custom.html

API 不公开服务

https://zelikk.blogspot.com/2022/07/url-shorten-worker-api-password.html

页面缓存设置过的短链

https://zelikk.blogspot.com/2022/08/url-shorten-worker-localstorage.html

长链接文本框预搜索localStorage

https://zelikk.blogspot.com/2022/08/url-shorten-worker-bootstrap-list-group-oninput.html

增加删除某条短链的按钮

https://zelikk.blogspot.com/2022/08/url-shorten-worker-delete-kv-localstorage.html

const config = {
no_ref: "off", //Control the HTTP referrer header, if you want to create an anonymous link that will hide the HTTP Referer header, please set to "on" .
theme:"",//Homepage theme, use the empty value for default theme. To use urlcool theme, please fill with "theme/urlcool" .
cors: "on",//Allow Cross-origin resource sharing for API requests.
unique_link:false,//If it is true, the same long url will be shorten into the same short url
custom_link:true,//Allow users to customize the short url.
}

const html404 = `<!DOCTYPE html>
<html>
<body>
  <h1>404 Not Found.</h1>
  <p>The url you visit is not found.</p>
  <p> <a href="https://github.com/crazypeace/Url-Shorten-Worker/" target="_self">Fork me on GitHub</a> </p>
</body>
</html>`

let response_header={
  "content-type": "text/html;charset=UTF-8",
} 

if (config.cors=="on"){
  response_header={
  "content-type": "text/html;charset=UTF-8",
  "Access-Control-Allow-Origin":"*",
  "Access-Control-Allow-Methods": "POST",
  }
}

async function randomString(len) {
  len = len || 6;
  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 sha512(url){
    url = new TextEncoder().encode(url)

    const url_digest = await crypto.subtle.digest(
      {
        name: "SHA-512",
      },
      url, // The data you want to hash as an ArrayBuffer
    )
    const hashArray = Array.from(new Uint8Array(url_digest)); // convert buffer to byte array
    const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
    //console.log(hashHex)
    return hashHex
}
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 save_url(URL){
    let random_key=await randomString()
    let is_exist=await LINKS.get(random_key)
    console.log(is_exist)
    if (is_exist == null)
        return await LINKS.put(random_key, URL),random_key
    else
        save_url(URL)
}
async function is_url_exist(url_sha512){
  let is_exist = await LINKS.get(url_sha512)
  console.log(is_exist)
  if (is_exist == null) {
    return false
  }else{
    return is_exist
  }
}
async function handleRequest(request) {
  console.log(request)

  // 查KV中的password对应的值
  const password_value = await LINKS.get("password");

  if (request.method === "POST") {
    let req=await request.json()
    let req_cmd=req["cmd"]
    if (req_cmd == "add") {
      let req_url=req["url"]
      let req_keyPhrase=req["keyPhrase"]
      let req_password=req["password"]

      console.log(req_url)
      console.log(req_keyPhrase)
      console.log(req_password)
      if(!await checkURL(req_url)){
        return new Response(`{"status":500,"key": "", "error":": Error: Url illegal."}`, {
          headers: response_header,
        })
      }

      if (req_password != password_value) {
        return new Response(`{"status":500,"key": "", "error":": Error: Invalid password."}`, {
          headers: response_header,
        })
      }

      let stat,random_key
      if (config.custom_link && (req_keyPhrase != "")){
        let is_exist=await LINKS.get(req_keyPhrase)
        if (is_exist != null) {
          return new Response(`{"status":500,"key": "", "error":": Error: Custom shortURL existed."}`, {
            headers: response_header,
          })
        }else{
          random_key = req_keyPhrase
          stat, await LINKS.put(req_keyPhrase, req_url)
        }
      } else if (config.unique_link){
        let url_sha512 = await sha512(req_url)
        let url_key = await is_url_exist(url_sha512)
        if(url_key){
          random_key = url_key
        }else{
          stat,random_key=await save_url(req_url)
          if (typeof(stat) == "undefined"){
            console.log(await LINKS.put(url_sha512,random_key))
          }
        }
      }else{
        stat,random_key=await save_url(req_url)
      }
      console.log(stat)
      if (typeof(stat) == "undefined"){
        return new Response(`{"status":200, "key":"`+random_key+`", "error": ""}`, {
          headers: response_header,
        })
      }else{
        return new Response(`{"status":500, "key": "", "error":": Error:Reach the KV write limitation."}`, {
          headers: response_header,
        })
      }
    } else if (req_cmd == "del") {
      let req_keyPhrase=req["keyPhrase"]
      let req_password=req["password"]

      if (req_password != password_value) {
        return new Response(`{"status":500,"key": "", "error":": Error: Invalid password."}`, {
          headers: response_header,
        })
      }

      await LINKS.delete(req_keyPhrase)
      return new Response(`{"status":200}`, {
        headers: response_header,
      })
    }

  }else if(request.method === "OPTIONS"){  
      return new Response(``, {
      headers: response_header,
    })
  }

  const requestURL = new URL(request.url)
  const path = requestURL.pathname.split("/")[1]
  const params = requestURL.search;

  console.log(path)
  if(!path){
    return Response.redirect("https://zelikk.blogspot.com/search/label/Url-Shorten-Worker", 302)
    /* new Response(html404, {
      headers: {
        "content-type": "text/html;charset=UTF-8",
      },
      status: 404
    }) */
  }
  
  // 如果path符合password 显示应用界面
  if (path==password_value){  
    let index= await fetch("https://crazypeace.github.io/Url-Shorten-Worker/"+config.theme+"/index.html")
    index=await index.text()
    index=index.replace(/__PASSWORD__/gm, password_value)
    return new Response(index, {
      headers: {
        "content-type": "text/html;charset=UTF-8",
      },
    })
  }

  const value = await LINKS.get(path);
  let location ;

  if(params) {
    location = value + params
  } else {
      location = value
  }
  console.log(value)
  
  if (location) {
    if (config.no_ref=="on"){
      let no_ref= await fetch("https://crazypeace.github.io/Url-Shorten-Worker/no-ref.html")
      no_ref=await no_ref.text()
      no_ref=no_ref.replace(/{Replace}/gm, location)
      return new Response(no_ref, {
        headers: {
          "content-type": "text/html;charset=UTF-8",
        },
      })
    }else{
      return Response.redirect(location, 302)
    }    
  }
  // If request not in kv, return 404
  return new Response(html404, {
    headers: {
      "content-type": "text/html;charset=UTF-8",
    },
    status: 404
  })
}

addEventListener("fetch", async event => {
  event.respondWith(handleRequest(event.request))
})

注意:修改版搭建完成后要访问,你的worker域名/url来打开使用页面

原版

https://github.com/xyTom/Url-Shorten-Worker/blob/main/index.js

const config = {
no_ref: "off", //Control the HTTP referrer header, if you want to create an anonymous link that will hide the HTTP Referer header, please set to "on" .
theme:"",//Homepage theme, use the empty value for default theme. To use urlcool theme, please fill with "theme/urlcool" .
cors: "on",//Allow Cross-origin resource sharing for API requests.
unique_link:false,//If it is true, the same long url will be shorten into the same short url
custom_link:false,//Allow users to customize the short url.
}

const html404 = `<!DOCTYPE html>
<body>
  <h1>404 Not Found.</h1>
  <p>The url you visit is not found.</p>
  <a href="https://github.com/xyTom/Url-Shorten-Worker/" target="_self">Fork me on GitHub</a>
</body>`

let response_header={
  "content-type": "text/html;charset=UTF-8",
} 

if (config.cors=="on"){
  response_header={
  "content-type": "text/html;charset=UTF-8",
  "Access-Control-Allow-Origin":"*",
  "Access-Control-Allow-Methods": "POST",
  }
}

async function randomString(len) {
  len = len || 6;
  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 sha512(url){
    url = new TextEncoder().encode(url)

    const url_digest = await crypto.subtle.digest(
      {
        name: "SHA-512",
      },
      url, // The data you want to hash as an ArrayBuffer
    )
    const hashArray = Array.from(new Uint8Array(url_digest)); // convert buffer to byte array
    const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
    //console.log(hashHex)
    return hashHex
}
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 save_url(URL){
    let random_key=await randomString()
    let is_exist=await LINKS.get(random_key)
    console.log(is_exist)
    if (is_exist == null)
        return await LINKS.put(random_key, URL),random_key
    else
        save_url(URL)
}
async function is_url_exist(url_sha512){
  let is_exist = await LINKS.get(url_sha512)
  console.log(is_exist)
  if (is_exist == null) {
    return false
  }else{
    return is_exist
  }
}
async function handleRequest(request) {
  console.log(request)
  if (request.method === "POST") {
    let req=await request.json()
    console.log(req["url"])
    if(!await checkURL(req["url"])){
    return new Response(`{"status":500,"key":": Error: Url illegal."}`, {
      headers: response_header,
    })}
    let stat,random_key
    if (config.unique_link){
      let url_sha512 = await sha512(req["url"])
      let url_key = await is_url_exist(url_sha512)
      if(url_key){
        random_key = url_key
      }else{
        stat,random_key=await save_url(req["url"])
        if (typeof(stat) == "undefined"){
          console.log(await LINKS.put(url_sha512,random_key))
        }
      }
    }else{
      stat,random_key=await save_url(req["url"])
    }
    console.log(stat)
    if (typeof(stat) == "undefined"){
      return new Response(`{"status":200,"key":"/`+random_key+`"}`, {
      headers: response_header,
    })
    }else{
      return new Response(`{"status":200,"key":": Error:Reach the KV write limitation."}`, {
      headers: response_header,
    })}
  }else if(request.method === "OPTIONS"){  
      return new Response(``, {
      headers: response_header,
    })

  }

  const requestURL = new URL(request.url)
  const path = requestURL.pathname.split("/")[1]
  const params = requestURL.search;

  console.log(path)
  if(!path){

    const html= await fetch("https://xytom.github.io/Url-Shorten-Worker/"+config.theme+"/index.html")
    
    return new Response(await html.text(), {
    headers: {
      "content-type": "text/html;charset=UTF-8",
    },
  })
  }

  const value = await LINKS.get(path);
  let location ;

  if(params) {
    location = value + params
  } else {
      location = value
  }
  console.log(value)
  

  if (location) {
    if (config.no_ref=="on"){
      let no_ref= await fetch("https://xytom.github.io/Url-Shorten-Worker/no-ref.html")
      no_ref=await no_ref.text()
      no_ref=no_ref.replace(/{Replace}/gm, location)
      return new Response(no_ref, {
      headers: {
        "content-type": "text/html;charset=UTF-8",
      },
    })
    }else{
      return Response.redirect(location, 302)
    }
    
  }
  // If request not in kv, return 404
  return new Response(html404, {
    headers: {
      "content-type": "text/html;charset=UTF-8",
    },
    status: 404
  })
}



addEventListener("fetch", async event => {
  event.respondWith(handleRequest(event.request))
})

10

绑定自己的域名

添加一个a记录,解析到任意ip地址

11

添加路由

12

13

访问域名

原版

14

修改版

我搭建的:https://url.xwsm.tk/url

15

0

评论区