源码 GitHub: https://github.com/xyTom/Url-Shorten-Worker/
修改版源码 GitHub: https://github.com/crazypeace/Url-Shorten-Worker
申请Cloudflare账号,略。
创建一个KV
记住这个KV的名字,以 url为例
查看此KV
添加一个条目Entry
密钥key为password,值为一个随机字符串.
* password这个key是在脚本中要引用的,所以要设置这个。
随机字符串以 url为例
创建Worker服务
设置绑定KV
变量名称必须设置为 LINKS, KV的名字选刚刚创建的 url
LINKS 是在脚本中要引用的,所以要设置这个。换句话说,如果你使用别的脚本,可能这个变量名称就不是LINKS了。
编辑Worker的脚本
把原有的内容全部删掉,换成: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))
})
绑定自己的域名
添加一个a记录,解析到任意ip地址
添加路由
访问域名
原版
修改版
我搭建的:https://url.xwsm.tk/url