三步带你开发一个短链接生成平台

GrapeCityChina:前端时间在开发 [葡萄城社区] 公众号时有一个功能是需要用网页授权认证地址生成二维码,但类似像下面这样的 Url 即便是看也觉得很头疼了 https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxxxxxxxxxxxxxxxxx&redirect_uri=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&response_type=code&scope=snsapi_base&state=STATE&connect_redirect=1#wechat_redirect

用这个地址生成的二维码也是密密麻麻,虽不影响微信长按扫码,一旦二维码尺寸缩一点点,图片马上就会糊掉,导致摄像头直接扫码会难以识别。

那这种情况下, 我们自然就会想到如果使用短链接减少 url 的字符,生成的码自然就会变得容易识别了,同时还会使 url 更美观且易于转发。现在市面上可用的就是微博的 t.cn 和一些第三方的生成短链接工具,但这两类工具都有一些使用上的问题,例如:t.cn 现在的规则是会出现一个中转页不会直接跳转,而第三方的工具因为是一个公共平台,有时可能会因一些不良信息导致整个平台无法访问。

那与其这样,不如我们自己来实现一个短链接平台吧,实现一个短链接平台原理上也非常简单,搞定两部分就行了:1.保存长短链接的对应关系。2.通过短链接查询长连接并重定向。

为了高效,我这使用的是 node 和 mongodb,下面我们就来开始动手吧。

首先,我们先创建一个 express 工程

express -e demo

change directory: > cd demo install dependencies: > npm install run the app: > SET DEBUG=demo:* & npm start

然后进入 demo 目录并安装 express 必要依赖

npm install

同时通过 npm 安装我们需要用到的 mongoose 和 shortid 和 body-parser

npm install mongoose
npm install shortid
npm install body-parser

下面分别对使用到的这三个包简单说明一下:

  • 在这个应用中,我们使用了 mongodb,之所以选择它是因为执行高效且低开销,所以执行起来也很高效,不过如果使用其他数据库也是没问题的。这里的mongoose就是 npm 的一个包,主要是为程序提供连接 mongodb 并增删查改的功能。
  • 通过使用shortid可以生成一个指定字符不重复的编码,便于我们生成类似 xxx.com/ngTsfdgh 类似红字部分的编码。
  • 由于我们生成短链接部分的 api 使用的是 post 方法,使用body-parser可以多扩展一种 body 编码类型解析能力。

首先设置 MongoDB 的连接信息

module.exports = {
mongo_base_connection_url: 'mongodb://localhost:27017',
mongo_db: 'mongodb://localhost:27017/shorturl',
mongo_options: {
autoReconnect: true,
keepAlive: true,
reconnectTries: 50,
reconnectInterval: 1000,
connectTimeoutMS: 5000000,
}
}
console.log("Connection local mongo db");

数据库模型定义

因为我们的对应关系是需要通过短链接查询长连接,所以这里我们主要以存储短链接和长连接为主,另外大家也可以根据自己需要添加链接点击统计之类的字段,方便后期统计。

var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var urlSchema = new Schema({
shortUrl: String,
longUrl: String
});

module.exports = mongoose.model('UrlTable', urlSchema);

定义 express 路由

因为这个应用我们只有生成和 Redirect 两个功能,所以这里只有两个页面即可完成所有工作。

var index = require('./routes/index');
var url = require('./routes/url');
app.use('/', index);
app.use('/url', url);

生成短链接页面

const express = require("express");
const router = express.Router();
const shortId = require('shortid');
const UrlTable = require('../models/urltable');
const mongoose = require('mongoose');
var setup = require('../dbconfig/db');

router.post('/', function(req, res, next) {
var params = req.body;
var url = params.longUrl;
shortId.characters(' 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ^*')
var shortid = shortId.generate();
var objurl = { shortUrl: shortid, longUrl: url};
mongoose.connect(setup.mongo_db, setup.mongo_options);
UrlTable.create(objurl, function (err, objurl) {
//if (err) console.log(err);
res.send("http://localhost:3000/" + shortid);
});
return;
});

指定生成 shortId 字符的范围并生成:

shortId.characters('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')

var shortid = shortId.generate();

为数据库构建符合要求的数据模型:

var objurl = { shortUrl: shortid, longUrl: url};

最后,连接数据库并保存后将短链接结果返回客户端:

mongoose.connect(setup.mongo_db, setup.mongo_options);

UrlTable.create(objurl, function (err, objurl) {

//if (err) console.log(err);

res.send("http://localhost:3000/" + shortid);

});

短链接跳转页面

const express = require("express");
const router = express.Router();
const UrlTable = require('../models/urltable');
const mongoose = require('mongoose');
var setup = require('../dbconfig/db');

router.get('/:shortUrl', function (req, res, next) {
var shortUrl = req.params.shortUrl;
mongoose.connect(setup.mongo_db, setup.mongo_options);
UrlTable.findOne({ shortUrl:shortUrl }).then((result) => {
//待添加错误处理
res.redirect(result.longUrl);
})
});

module.exports = router;

这个页面为了便于快速跳转,我们就使用 get 接收参数,这个页面功能就很简单了,接参查询并跳转。

接收短链接码

var shortUrl = req.params.shortUrl;

连接数据库查询并跳转

mongoose.connect(setup.mongo_db, setup.mongo_options);

UrlTable.findOne({ shortUrl:shortUrl }).then((result) => {

//待添加错误处理

res.redirect(result.longUrl);

})

后期大家可以对一些错误异常处理,数据统计等做一些增强,这里就不做补充了。

下面让我们启用应用开始测试吧。

启动应用并测试

npm start

启动后,默认的访问端口为 3000,我们首先测试下短链接生成页,这里我们 post 一个名为 longUrl 的长链接参数,数据对象为:

{"longUrl" : "https://demo.grapecity.com.cn/spreadjs/SpreadJSTutorial/features/tables/basic-table/purejs"}

三步带你开发一个短链接生成平台

成功升成了如下短链接:

http://localhost:3000/iGE6ZlDmh

我们只要通过访问短链接能正常跳转至保存的长连接即可。

三步带你开发一个短链接生成平台

这样就测试通过了,其实代码量不大,原理也很简单。大家如果自己有较短的域名的话,上线后会让链接变得更短、更美观,这样一个属于我们自己短链接生成平台就开发完成了。下面附上源码,执行 npm install 即可自动安装所有依赖,如果大家有问题,可通过评论区告诉我。

源码下载>>

opengps:首先得有一个短域名,我找了好几年只看好一个中意的(4 位 cn),已在个人网站下用了 3 年

memedahui:@Livid

easonHHH:直接拷贝代码是真的没有看下来的欲望,建议代码块格式一下

xuxuxu123:有个,四位 .com 域名;
65we.com
有需要的嘛

yamedie:貌似是 KPI 帖

有个疑问:
router.get('/:shortUrl', function (req, res, next) { var shortUrl = req.params.shortUrl; mongoose.connect(setup.mongo_db, setup.mongo_options); UrlTable.findOne({ shortUrl:shortUrl }).then((result) => { //待添加错误处理 res.redirect(result.longUrl); }) });

楼主这样写, 每个短链接的 get 请求发来, 都现连接数据库, 效率也太低了吧? 而且连接数据库是异步的, 需要回调函数或者 async/await 执行后面的语句, 这里直接写成同步写法了, 让我有点摸不着头脑 ?

zpfhbyx:yourls 不香么。。

shc:感谢楼主的教程,那就搭车出几个短域名吧,pp.tc, mv.mk, 58.si, us.rs, vps.vc, git.tg, sir.sr, ts.st ,感兴趣的私聊?

GrapeCityChina:@yamedie 你的建议很好,你这样会使效率更高,这也是一个可优化的点

ylsc633:那我也搭车出个域名?

guof.com

tsvv.com
qq-v.com

mongoose 聚合管道查询, list 中的子对象如何关联?

ideacco:RT,使用 mongoose,有如下两个数据,我想把产品参数据表,对应的产品查询出来,我目前只会查询一级的,在 Array 里面包裹的数据就不知道怎么取出来了,看了一天的官网文档也没看明白……惭愧惭愧,求大神给指个道吧。 示例数据如下: // 产品数据表 product { "uid": "5f460572f639b62baa839baa",…

Python Jinja2从后端分配javascript var - javascript

我正在for循环中,我需要将python值分配给javascript变量,但我实际上无法使其工作:({% for row in temp %} var year = {{ row[0]|safe }} {% endfor %} 我已经尝试了很多方法,但它总是会给我Uncaught SyntaxError: Unexpected token var 正确的语法…

var_上的“无可用完成” - php

我已经老化了完成的问题。现在我没有任何建议。当然,我可以键入var_dump,但是它对自动补全比较满意。我正在使用带有PDT 2.1的Eclipse PHP Ide 3.5。 参考方案 在Eclipse PHP Project中将“ Core API”添加到“ PHP Language Library”。解:右键单击Eclipse PHP项目->属性-…

使用php echo定义一个javascript var - javascript

我已经看到了对该问题的多个答复-因此,我敢肯定有人会很快将其标记为重复,但是我在任何其他线程中都没有看到该特定问题的答案。我有两个测试文件:a.php和a.js在a.php中,我定义$q = $_GET['q']; 效果很好。然后,我调用一个单独的a.js文件,其中有:var partNumber = " <?php ec…

LeetCode题解水壶问题

给你一个装满水的 8 升满壶和两个分别是 5 升、3 升的空壶,请想个优雅的办法,使得其中一个水壶恰好装 4 升水,每一步的操作只能是倒空或倒满。题解:``` .js/** * 思路: * 每个容器有两个选择,比如:A,可以倒入B,或者倒入C * 同样,B可以倒入A,也可以倒入C * 那么每次就有8种可能 * * 每产生一种可能,顺着这种可能的结果,继续去遍…