Nodejs+mySql实现长地址转短地址
一、开发原因
之前公司用一些在线的转短地址网站,但出来的的地址输入没规则,输入太麻烦了,而且扫码还需要安装一个扫码的软件,在一个就是不能转换本地代理的地址(例:http://192.168.1.200:8080),心累。正好公司有个闲置的电脑做服务器,想着干嘛不搞个本地的转短地址工具,这样可以随意设置,想咋弄就咋弄。
注:这个插件没有部署到服务器上,只是在本地搭建了一个可运行环境,在局域网内可以随意访问。不过只要部署到服务器,再给个域名,就完全可以用,童鞋们可以自行补全。
二、开发环境
- 系统环境:macOS, Version 10.13.1
- nodejs (v9.2.0) 后台语言
- mysql (v5.7.17) 数据库
- MySQLWorkbench (v6.3.10) 数据库可视化工具
- Chrome Extension Chrome插件
三、分析开发流程
- 获取长链接地址
- 把地址传给后台
- 查找数据库里面是否存在改地址
- 生成短地址
- 返回短地址数据
四、开发流程
4.1 分析数据库、搭建数据库
数据库至少需要三个字段(id、长地址、短地址),三个字段一目了然就不做介绍了。装好mySql后大神可以直接用命令行建数据库,我这里用的一个可视化工具(MySQLWorkbench)建的数据库。对于数据库最重要的一点是要设置字符集格式,因为地址中会出现一些类似xxx=xxx&xxx=xxx这样的数据,这样在做比较的时候就会报错。可以添加如下代码解决:
1 SET collation_connection = 'utf8_general_ci'; 2 ALTER DATABASE url CHARACTER SET utf8 COLLATE utf8_general_ci; 3 ALTER TABLE url.shortUrl CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;
4.2 搭建后台程序框架
后台框架很简单,主要两个文件就搞定,结构如下:
app.js文件用来开本地服务,以及处理传进来的信息(长地址)。mysqlPool.js用来操作数据库。
app.js:
1 var http = require('http'); 2 var url = require('url'); 3 var UrlInfo = require('./routes/mysqlPool'); 4 5 var serve = http.createServer(function(req, res){ 6 // 过滤favicon.ico请求 7 if(req.url !== '/favicon.ico'){ 8 var obj = url.parse(req.url, true); 9 var pathname = obj.pathname; 10 // 分割地址信息 11 var nameArr = pathname.toString().split('/'); 12 13 if(nameArr[1] === ''){ 14 res.end(); 15 }else if(nameArr[1] === 'insert'){ // 表示插入操作 16 var firstChart = obj.search.indexOf('='); 17 //获取需要存储的长地址 18 var longAddress = obj.search.substring(firstChart+1, obj.search.length); 19 // 根据长地址查询数据库是否存在此条信息。 20 UrlInfo.getUrlInfoByLongAddress(longAddress, function(err, reuslt){ 21 if(err){ 22 // 这里对数据库的字符集设置有要求,如果设置不对则会报错,具体设置参考上面数据库搭建 23 console.log(err); 24 }else{ 25 // 如果存在这条信息,则返回短地址 26 if(reuslt.length > 0){ 27 var longUrl = reuslt[0].longAddress; 28 var shortUrl = reuslt[0].shortAddress; 29 var data = { 30 'longAddress': longUrl, 31 'shortAddress': shortUrl 32 }; 33 res.write(JSON.stringify(data)); 34 res.end(); 35 }else{ 36 // 查询最大的id值 37 UrlInfo.getMaxId(function(err, reuslt){ 38 var maxID = reuslt[0]['max(id)']; 39 // 如果id号大于或等于99则清空数据库,保证短地址最短,这个值看需求设置 40 if(maxID >= 99){ 41 UrlInfo.deleteAllData(function(err, reuslt){ 42 if(reuslt){ 43 maxID = 0; 44 UrlInfo.insertInfo(maxID + 1, longAddress, function(err, reuslt, backData){ 45 if(reuslt){ 46 var data = { 47 'longAddress': backData.longAddress, 48 'shortAddress': backData.shortAddress 49 }; 50 res.write(JSON.stringify(data)); 51 } 52 res.end(); 53 }); 54 }else{ 55 res.end(); 56 } 57 }); 58 }else{ 59 // 插入新信息并返回短地址 60 UrlInfo.insertInfo(maxID + 1, longAddress, function(err, reuslt, backData){ 61 if(reuslt){ 62 var data = { 63 'longAddress': backData.longAddress, 64 'shortAddress': backData.shortAddress 65 }; 66 res.write(JSON.stringify(data)); 67 res.end(); 68 }else{ 69 res.end(); 70 } 71 }); 72 } 73 }); 74 } 75 } 76 }); 77 }else{ // 表示请求操作 78 UrlInfo.getUrlInfoById(nameArr[1], function(err, reuslt){ 79 // 如果请求格式错误则跳到百度去(免费打了个广告) 80 if(err){ 81 res.writeHead(302, { 82 'Location': 'http://www.baidu.com' 83 }); 84 }else{ 85 // 根据id获取到对应的短地址 86 var longUrl = reuslt[0].longAddress; 87 // 重定向操作,实现短地址跳转到长地址 88 res.writeHead(302, { 89 'Location': longUrl 90 }); 91 } 92 res.end(); 93 }); 94 } 95 } 96 }).listen(3000);
mysqlPool.js:
1 var mysql = require('mysql'); 2 3 var ipConfig = 'http://192.168.1.200:3000/'; 4 5 //创建一个连接池 6 var pool = mysql.createPool({ 7 host: '127.0.0.1', 8 user: 'root', 9 password: '1234', 10 database: 'url', 11 port: '3306' 12 }); 13 14 pool.on('connection', function(connection) { 15 connection.query('SET SESSION auto_increment_increment=1'); 16 }); 17 18 19 module.exports = { 20 // 这里对错误用try,catch抓取,防止错误导致服务器关闭,当然这些错误都没处理,要想完整一些可以自行处理 21 // 这里每个方法都有一个数据库链接操作,可以提炼公共的方法来简化代码 22 getUrlInfoById: function(id, callback){ 23 pool.getConnection(function(err, connection){ 24 connection.query("USE url", function(err){ 25 if (err) { 26 console.log("USE Error: " + err.message); 27 return; 28 } 29 console.log('USE succeed'); 30 }); 31 32 connection.query("select * from shorturl where id=?", [id], function(err, result){ 33 try{ 34 connection.release(); 35 callback(err, result); 36 }catch(errInfo){ 37 console.log("select User_Sql Error: " + errInfo.message); 38 callback(errInfo, result); 39 } 40 }); 41 }); 42 }, 43 getUrlInfoByLongAddress: function(longAddress, callback){ 44 pool.getConnection(function(err, connection){ 45 connection.query("USE url", function(err){ 46 if (err) { 47 console.log("USE Error: " + err.message); 48 return; 49 } 50 console.log('USE succeed'); 51 }); 52 53 connection.query("select * from shorturl where longAddress=?", [longAddress], function(err, result){ 54 try{ 55 connection.release(); 56 callback(err, result); 57 }catch(errInfo){ 58 console.log("select User_Sql Error: " + errInfo.message); 59 callback(errInfo, result); 60 } 61 }); 62 }); 63 }, 64 getMaxId: function(callback){ 65 pool.getConnection(function(err, connection){ 66 connection.query("USE url", function(err){ 67 if (err) { 68 console.log("USE Error: " + err.message); 69 return; 70 } 71 console.log('USE succeed'); 72 }); 73 74 connection.query("select max(id) from shorturl", function(err, result){ 75 try{ 76 connection.release(); 77 callback(err, result); 78 }catch(errInfo){ 79 console.log("select User_Sql Error: " + errInfo.message); 80 callback(errInfo, result); 81 } 82 }); 83 }); 84 }, 85 insertInfo: function(id, longAddress, callback){ 86 pool.getConnection(function(err, connection){ 87 connection.query("USE url", function(err){ 88 if (err) { 89 console.log("USE Error: " + err.message); 90 return; 91 } 92 console.log('USE succeed'); 93 }); 94 95 connection.query("insert into shorturl(id,longAddress,shortAddress) values(?,?,?)", [id, longAddress, ipConfig + id], function(err, result){ 96 try{ 97 connection.release(); 98 callback(err, result, { 99 'longAddress': longAddress, 100 'shortAddress': ipConfig + id 101 }); 102 }catch(errInfo){ 103 console.log("select User_Sql Error: " + errInfo.message); 104 callback(errInfo, result, { 105 'longAddress': longAddress, 106 'shortAddress': ipConfig + id 107 }); 108 } 109 }); 110 }); 111 }, 112 deleteAllData: function(callback){ 113 pool.getConnection(function(err, connection){ 114 connection.query("USE url", function(err){ 115 if (err) { 116 console.log("USE Error: " + err.message); 117 return; 118 } 119 console.log('USE succeed'); 120 }); 121 122 connection.query("delete from shorturl where 1=1", function(err, result){ 123 try{ 124 connection.release(); 125 callback(err, result); 126 }catch(errInfo){ 127 console.log("select User_Sql Error: " + errInfo.message); 128 callback(errInfo, result); 129 } 130 }); 131 }); 132 }, 133 };
这里数据库操作很简洁,因为使用人数比较少,所以就没有做什么数据库回滚、死锁等操作,如果面向人群比较多,这些并发性还是要考虑的。这里就随意啦~~~
到这里整个工具基本上完成了,但是要获取到需要转换的长地址总不能Ctrl+C、Ctrl+V吧。这样非人性化的工具,咱码农可拿不出手的。所以用Chrome插件工具就可以完美完成这个任务。
4.3 Chrome插件开发
这里插件的具体配置、开发我就不啰嗦了,官方文档分分钟搞定。我就贴一下配置文件和主要实现代码吧。
目录结构:
manifest.json:(Chrome插件配置文件)
1 { 2 "name": "Link", 3 "version": "0.1", 4 "manifest_version": 2, 5 "description": "long to short", 6 "icons": { 7 "100": "image/icon.png" 8 }, 9 "browser_action": { 10 "default_icon": "image/icon.png", 11 "default_popup": "popup.html" 12 }, 13 "background": { 14 "scripts": ["bjs/jquery-2.0.3.min.js", "bjs/background.js"] 15 }, 16 "permissions": [ 17 "tabs" 18 ], 19 "content_scripts": [{ 20 "matches": ["<all_urls>"], 21 "js": ["bjs/jquery-2.0.3.min.js"], 22 "all_frames": true, 23 "match_about_blank": true, 24 "run_at": "document_start" 25 }] 26 }
popup.js:
1 $(function () { 2 getCurrentTab(function(tabs){ 3 if(tabs){ 4 // 设置服务器的ip地址 5 var joinIP = 'http://192.168.1.200:3000/insert?longAddress='; 6 // ajax访问服务器 7 $.getJSON(joinIP + tabs.url, function (data) { 8 $('.long-url').html(tabs.url); 9 $('.short-url').html(data.shortAddress); 10 $('.loading-box').hide(); 11 console.log(data); 12 }); 13 }else{ 14 console.log('no tab'); 15 } 16 }); 17 // 获取到当前网站信息 18 function getCurrentTab(callback) { 19 chrome.tabs.query({ 20 active: true, 21 currentWindow: true 22 }, function (tabs) { 23 if (callback) callback(tabs.length ? tabs[0] : null); 24 }); 25 } 26 })
五、启动方式
- 添加Chrome插件到Chrome浏览器
- 在命令行定位到项目工程文件
- 运行node app命令开启本地服务
- 找一个地址,点击那个插件生成短地址测试
- 完成
六、结果截图
亲测有效~~~
七、迁移到Windows服务器
-
系统环境:win7系统(32位)------ 一脸懵逼的吐槽公司这台闲置的电脑,这配置~~~
-
nodejs (v8.11.2) 后台语言 ------ 直接下载msi文件点击安装
-
mysql (v8.....忘记了) 数据库 ------ 下载msi文件跟着步骤安装
-
MySQLWorkbench (v6.3.10) 数据库可视化工具
- 再次吐槽一下这台电脑,.Net Framework版本低的不要不要的,mySql软件需要的环境都要升级,折腾一下午终于搞定,至于配置方式可以百度解决
- Windows有个好处就是可以设置开机运行脚本,这样每次启动就可以自动开启服务了,不需要每次手动去开。
- 新建一个txt文件,里面输入node C:\url\app(因为我把工程文件就放在了c盘下面),如果路径不同可以自行调整
- 保存txt文件,然后把文件后缀改成bat,然后添加到开机启动项里面,这里推荐一篇关于设置启动项的文章:http://blog.51cto.com/10676568/1974842
- 重启电脑测试~~~