「shURL 短网址」

Github 仓库

欢迎使用 shURL\texttt{shURL}
这是 shURL\texttt{shURL} 工具的使用文档。

图:最终效果


综述

此工具为一「短网址」工具。

何为短网址?简单来讲,就是以工具将原网址缩短长度,使访问更加便捷。

举个简单的例子:

原网址:https://www.bilibili.com/video/BV1DK4y1z7wq/?vd_source=c2c603cbba8a549035c5aaed2e9faa97
短网址:https://daoxi365.dpdns.org/?x=pkCf

显然,它实现链接转换是需要后端服务器、数据库的。但是,此工具选择了基于 LeanCloud 的线上储存,因此可以运行于静态网站,如 Github PagesNetlify 等。

操作步骤

  1. 注册或登录一个 LeanCloud​ 帐号。LeanCloud 账号分为国际、国内两种,如果你使用国外网络环境或用户面向国外,推荐使用国际版。反之,则建议使用国内版。
    本网站当前使用国内版 LeanCloud,可大幅提升访问速度。但是注册国内版 LeanCloud 账号需要实名认证。

    图:国际版账号注册图

  2. 创建一个新应用。应用名称随便写;计价方案选择开发版,否则会被收费。

  3. 进入刚刚创建的应用,左侧边栏下划到最后,在“设置”中找到“应用凭证”,在右侧按如图方式复制凭证信息。
    注意:第四步 国内版 用户必须保留。国际版用户可以不使用此 rest api 地址。

    图:我已配置好的一个国内版应用的凭证

  4. 打开 /js/app.js ,按注释(绿字)要求修改相关内容。

  5. 本地测试。
    如果有 Python 环境,可以使用以下命令打开一个开发环境:

    1
    2
    python -m http.server 8000
    # 接下来你可以在 127.0.0.1:8000 访问到你的页面。

    图:测试

    图:测试

  6. 关于个性化:

    • 您可以修改 media 文件夹下的网站图标(favicon.ico)和标志(logo.png)。
    • 您可以自行修改网页样式,但是我希望您能保留帮助文档的链接。
  7. push 到远端。打开 pages 服务或用其他平台发布。

    图:提交后的样子

  8. 修改安全网址。

    图:修改安全网址的操作(用的旧图)

  9. 测试,完成。

补充

您可以在结构化数据控制台上增、删短网址。

原理解析

shURL 是我最初认识 LeanCloud 和 tailwindcss 的项目。以上技术栈均在原理中涉及。

shURL 的原理是建立一个长网址与随机字符串的映射关系,并存储在 LeanCloud 数据库中。

也就是说,用户每次提交原网址,shURL 都会生成一个随机字符串,并将其与长网址映射,存储在 LeanCloud 数据库中。每当用户将字符串通过接口传入 shURL 时,就会依据数据库存储重定向到原网址。

拆解 app.js

初始化 LC 对象,检测是否有 shURL 类:

1
2
3
4
5
6
7
AV.init({
appId: APPID,
appKey: APPKEY,
serverURL: REST_API,
});
AV.debug.enable();
const SHURL = AV.Object.extend("shURL");

这是一个创建最大长度为 4848 的随机字符串的方法。该字符串就是待生成的短网址链接代号。

1
2
3
4
5
6
7
8
9
10
function randomStr(len) {
if (len > 48) len = 48;
var $chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";
var maxPos = $chars.length;
var pwd = "";
for (var i = 0; i < len; i++) {
pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
}
return pwd;
}

在前端给出提示的方法:

1
2
3
4
function setNote(s) {
var x = document.getElementById("newURL");
x.innerHTML = s;
}

检测是否已经存在用户给出的原长网址的方法。如果有就返回其长度。

1
2
3
4
5
6
7
function checker(s) {
const query = new AV.Query("shURL");
query.equalTo("shortURL", s);
query.find().then((link) => {
return link.length;
});
}

生成短网址的方法。首先检测是否符合 URL 格式,然后检查是否已经存在该长网址的短网址,如果有就直接返回,否则生成随机字符串,并上传到数据库,同时把短网址返回到前端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
function make() {
try {
var ago = document.getElementById("ago");
var agoURL = ago.value;
var pattern =
/^((ht|f)tps?):\/\/([\w\-]+(\.[\w\-]+)*\/)*[\w\-]+(\.[\w\-]+)*\/?(\?([\w\-\.,@?^=%&:\/~\+#]*)+)?/;
if (!pattern.test(agoURL)) {
setNote(
'<b class="text-purple-700">您的输入似乎不是 URL,请重新输入。</b>'
);
return;
}
setNote(`<b class="text-state-800">请稍等!</b>`);

const query = new AV.Query("shURL");
query.equalTo("agoURL", agoURL);
query.find().then((link) => {
if (link.length >= 1) {
flag = true;
var shLink = link[0].get("shortURL");
var shURL =
`${WEBSITE}/` +
(GITHUB ? `${GITHUB_REPOSITORY}/` : ``) +
`?x=${shLink}`;
setNote(
`<b><a href="${shURL}" class="text-blue-700 hover:text-blue-800"><code>${shURL}</code></a></b>`
);
return;
} else {
var shLink = randomStr(LENGTH);
while (checker(shLink)) shLink = randomStr(LENGTH);
const todo = new SHURL();
todo.set("agoURL", agoURL);
todo.set("shortURL", shLink);
todo.save().then(
(todo) => {
var shURL =
`${WEBSITE}/` +
(GITHUB ? `${GITHUB_REPOSITORY}/` : ``) +
`?x=${shLink}`;
setNote(
`<b><a href="${shURL}" class="text-blue-700 hover:text-blue-800"><code>${shURL}</code></a></b>`
);
},
(error) => {
setNote(
`<b class="text-rose-600">发生错误(<code>CODE = ${error.code}</code>),请稍后再试。</b>`
);
}
);
}
});
} catch (err) {
setNote(
`<b class="text-rose-600">发生错误(<code>${err}</code>),请稍后再试。</b>`
);
}
}

如果用户给出了短网址,则需要根据数据库查询原来的长网址,并重定向到原网址。若不存在则报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function getName(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var r = window.location.search.substr(1).match(reg);
var context = "";
if (r != null) context = r[2];
reg = null;
r = null;
return context == null || context == "" || context == "undefined"
? "ERROR ERROR ERROR!!!"
: context;
}

function loadTo() {
try {
var x = getName("x");
if (x == "ERROR ERROR ERROR!!!") return;
var w = `${WEBSITE}/` + (GITHUB ? `${GITHUB_REPOSITORY}/` : ``);
setNote(
`<b class="text-amber-700">正在跳转:<code>${x}</code>;<a href="${w}" class="text-sky-600 hover:text-sky-700">取消此操作</a>。</b>`
);
const query = new AV.Query("shURL");
query.equalTo("shortURL", x);
query.find().then((link) => {
if (!link.length)
setNote(
`<b class="text-rose-600">发生错误,此链接尚未被注册或在数据库中被删除。</b>`
);
window.location.href = link[0].get("agoURL");
});
} catch (err) {
setNote(
`<b class="text-rose-600">发生错误(<code>${err}</code>),请稍后再试。</b>`
);
}
}

创建一个 SHURL 对象,完成初始化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const initial = new SHURL();
try {
const query = new AV.Query("shURL");
} catch (err) {
initial.set("agoURL", "index");
initial.set("shortURL", "index1");
initial.save().then(
(todo) => {},
(error) => {
setNote(
`<b class="text-rose-600">初始化失败(<code>CODE = ${err.code}</code>),请联系网站开发者。</b>`
);
}
);
}

关于前端

前端使用的是 tailwindcss 作为 CSS 框架。确实好使。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<!DOCTYPE html>

<html>
<head>
<meta charset="utf-8" />
<title>shURL 短网址</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="./media/favicon.ico" />
<!--
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/leancloud-storage@3.15.0/dist/av-min.js"></script>
-->
<script src="./js/leancloud-javascript-sdk-6f78e1c/dist/av-min.js"></script>
<script src="./js/tailwindcss_v3.4.1.js"></script>
</head>

<body>
<div
class="flex flex-col items-center justify-center h-screen bg-sky-100"
>
<img
src="./media/logo.png"
alt="logo"
class="w-20 h-auto mb-8 rounded-lg"
/>
<form
action="javascript:make();"
class="flex items-center justify-center w-1/2 bg-white rounded-full shadow-xl"
>
<input
type="text"
placeholder="转换为短网址"
id="ago"
class="w-full px-4 py-2 rounded-l-full focus:outline-none"
/>
<button
type="submit"
class="flex items-center justify-center px-4 py-2 text-white bg-emerald-700 rounded-r-full hover:bg-emerald-900 focus:outline-none"
>
<b>Go!</b>
</button>
</form>
<br /><br />
<p id="newURL">
<a
class="text-teal-500 hover:text-teal-600"
href="https://blog.daoxi365.top/posts/43801/"
><b>帮助文档:我也想创建一个这样的网站。</b></a
>
</p>
</div>
<script src="./js/app.js"></script>
<script>
loadTo();
</script>
</body>
</html>