短连接咱们或多或少都使用过,所谓短连接就是根据较长的原连接url生成一段较短的连接,访问短连接能够跳转到对应的原连接,这样作好处在于:1. url更加美观;2. 便于保存和传播;3. 某些网站内容发布有字数限制,短连接能够节约字数。node
短连接实现的原理很是简单,能够归纳为:git
根据以上思路,咱们本身也能够分分钟实现一个短连接生成服务。本文示例使用 node + express + mongodb。github
package.json:web
"dependencies": { "config": "^3.2.2", // 读取项目配置 "express": "^4.17.1", // web服务器 "mongoose": "^5.6.9", // 操做mongodb "shortid": "^2.2.14", // 生成不重复的惟一Id "valid-url": "^1.0.9" // 判断url格式是否正确 }
主要用于存放MongoDB的链接字符串和短连接的base url。mongodb
config/default.json:数据库
{ "mongoURI": "mongodb://localhost:27017/url-shorten-service", "baseUrl": "http://localhost:5000" }
config/db.js:express
const mongoose = require('mongoose'); const config = require('config'); const db = config.get('mongoURI'); const connectDB = async () => { try { await mongoose.connect(db, { useNewUrlParser: true }); console.log(`MongoDB Connected to: ${db}`); } catch (error) { console.error(error.message); process.exit(1); } } module.exports = connectDB;
index.js:npm
const express = require('express'); const connectDB = require('./config/db'); const app = express(); // 链接MongoDB connectDB(); app.use(express.json({ extended: false })); // 路由,稍后设置 app.use('/', require('./routes/index')); app.use('/api/url', require('./routes/url')); const port = 5000; app.listen(port, () => { console.log(`Server running on port ${port}`); });
咱们须要将原连接和对应短连接保存到数据库,简单起见,咱们只须要保存一个短连接编码,相应的短连接可使用base url和编码拼接而成。json
models/url.js:api
const mongoose = require('mongoose'); const urlSchema = new mongoose.Schema({ urlCode: String, longUrl: String }); module.exports = mongoose.model('Url', urlSchema);
这是咱们实现的关键一步,思路是:用户传入一个长连接,咱们首先使用 valid-url 判断传入的url是否合法,不合法则返回错误,若是合法咱们在数据库中搜索是否有该长连接的记录,若是有则直接返回该条记录,若是没有则生成一条新记录,并生成对应的短连接。借助于 shortId,咱们能够很方便的生成一个不重复的惟一编码。
routes/url.js:
const epxress = require("express"); const router = epxress.Router(); const validUrl = require('valid-url'); const shortId = require('shortid'); const config = require('config'); const Url = require('../models/url'); router.post('/shorten', async (req, res, next) => { const { longUrl } = req.body; if (validUrl.isUri(longUrl)) { try { let url = await Url.findOne({ longUrl }); if (url) { res.json({ shortUrl: `${config.get('baseUrl')}/${url.urlCode}` }); } else { const urlCode = shortId.generate(); url = new Url({ longUrl, urlCode }); await url.save(); res.json({ shortUrl: `${config.get('baseUrl')}/${urlCode}` }); } } catch (error) { res.status(500).json('Server error'); } } else { res.status(401).json('Invalid long url'); } }); module.exports = router;
最后一步很是简单,当用户访问咱们生成的短连接时,咱们根据url中的短连接编码查询到对应记录,若是存在对应记录咱们使用express的res.redirect
方法将访问重定向至原连接,若是不存在则返回错误。
routes/index.js
const epxress = require("express"); const router = epxress.Router(); const Url = require('../models/url'); router.get('/:code', async (req, res, next) => { try { const urlCode = req.params.code; const url = await Url.findOne({ urlCode }); if (url) { // 重定向至原连接 res.redirect(url.longUrl); } else { res.status(404).json("No url found"); } } catch (error) { res.status(500).json("Server error"); } }); module.exports = router;
测试一下:
访问短连接:
这样,一个简单的短连接生成服务就完成了,每每在咱们看来很神奇的技术其实背后的原理和实现很简单,但愿本文对你们有所启发。
最后,推荐你们使用 Fundebug,一款很好用的BUG监控工具~
本文Demo地址:https://github.com/MudOnTire/...