应用场景:发短信的时候,可能由于参数的问题导致链接过长,超出短信字数限制,所以链接需要越短越好
原理
生成一个唯一的标志,来对链接进行标记,存入数据库。如
{
fullUrl: 'https://www.baidu.com',
shortUrl: 'jgXqZSu8W'
}
也就是说,根据 shortUrl
的值,找到它的 fullUrl
,然后重定向跳转。
实现
1. Express 创建项目
- 新建文件夹
mkdir shortUrl
- 初始化项目
npm init -y
- 安装依赖包,请参照
package.json
,npm i -S express
- 在根目录新建
app.js
文件 - 修改
package.json
的运行命令,在 script 中添加"start": "node app.js"
; - 编写
app.js
const express = require('express');
const app = express();
app.get('/', async (req, res) => {
res.send('hello world')
});
app.listen(5000)
- 运行
npm start
, 打开页面locahost:5000
,可以看到 hello world 表示项目运行成功。大框架已经有了,接下来需要进行修修改改。
2. 创建数据库
数据库的操作大同小异,这边以 sqlite3
为例。因为不需要在本地安装客户端即可使用,比较方便。为了简化操作,另外安装了 sequelize
进行数据库操作。
- 在根目录新建文件夹
db
, 在该文件夹里新建文件index.js
,shortUrl.js
- 安装依赖
npm i -S shordid sqlite3 sequelize
首先,让我们编写shortUrl.js
,
// shortUrl.js
const shortId = require('shortid'); // 用于生成短链接的码
module.exports = (sequelize, DataTypes) => {
const ShortUrlModel = sequelize.define('ShortUrlModel', {
full: {
type: DataTypes.STRING
},
short: {
type: DataTypes.STRING,
defaultValue: shortId.generate
},
})
ShortUrlModel.associate = function (models) {
}
return ShortUrlModel
}
// config.js
const path = require('path');
module.exports = {
db: {
database: process.env.DB_NAME || 'shorturl',
user: process.env.DB_USER || 'shorturl',
password: process.env.DB_PASS || 'shorturl',
options: {
dialect: process.env.DIALECT || 'sqlite',
host: process.env.HOST || 'localhost',
storage: path.resolve(__dirname, './shorturl.sqlite')
}
}
}
然后,编写 index.js
// index.js
const {Sequelize} = require('sequelize');
const config = require('../config.js');
const fs = require('fs');
const path = require('path');
const db = {};
const sequelize = new Sequelize(
config.db.database,
config.db.user,
config.db.password,
config.db.options
);
// 将文件夹下的数据模型导入,这样就不用手动一个个写了
fs
.readdirSync(__dirname)
.filter((file) =>
file !== 'index.js'
)
.forEach((file) => {
const model = require(path.join(__dirname, file))(sequelize, Sequelize.DataTypes)
db[model.name] = model
})
// 抄过来的,我也不知道是啥意思,等知道了再补充
Object.keys(db).forEach(function (modelName) {
console.log(Object.keys(db))
if ('associate' in db[modelName]) {
db[modelName].associate(db)
}
})
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
3. 改写 app.js
const express = require('express');
const app = express();
const {sequelize, ShortUrlModel} = require('./db');
// sequelize连接数据库
sequelize.sync({force: true}) // force: true, 每次重启项目初始化的时候,会清空数据
.then(() => {
console.log(`Data base created`)
})
// 设置模版引擎
app.set('view engine', 'ejs');
app.use(express.urlencoded({ extended: false })); // 用于获取request的参数
app.get('/', async (req, res) => {
// 获取所有的链接,来进行渲染
const shortUrls = await ShortUrlModel.findAll();
res.render('index', {shortUrls});
});
app.post('/shortUrls', async (req, res) => {
// 提交链接数据,并保存
await ShortUrlModel.create(req.body);
res.redirect('/');
})
app.get('/:short', async (req, res) => {
// 根据短链接码找到这条数据,数据里头有完整链接
const shortUrl = await ShortUrlModel.findOne({
where: {
short: req.params.short
}
});
// 得到完整链接后,进行重定向
res.redirect(shortUrl.full)
})
app.listen(5000)
4. 编写 view/index.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<title>Document</title>
</head>
<body>
<div class="container">
<h1>URL Shrinker</h1>
<form action="/shortUrls" method="POST" class="my-4 form-inline">
<label for="full" class="sr-only">Url</label>
<input required placeholder="Url" type="url" name="full" id="full" class="form-control col mr-2">
<button class="btn btn-success" type="submit">Shrink</button>
</form>
<table class="table table-striped table-responsive">
<thead>
<tr>
<th>Full URL</th>
<th>Short URL</th>
</tr>
</thead>
<tbody>
<% shortUrls.forEach(shortUrl => { %>
<tr>
<td><a href="<%= shortUrl.full %>"><%= shortUrl.full %></a></td>
<td><a href="<%= shortUrl.short %>"><%= shortUrl.short %></a></td>
</tr>
<% }) %>
</tbody>
</table>
</div>
</body>
</html>