一、開發原因 之前公司用一些線上的轉短地址網站,但出來的的地址輸入沒規則,輸入太麻煩了,而且掃碼還需要安裝一個掃碼的軟體,在一個就是不能轉換本地代理的地址(例:http://192.168.1.200:8080),心累。正好公司有個閑置的電腦做伺服器,想著幹嘛不搞個本地的轉短地址工具,這樣可以隨意設 ...
一、開發原因
之前公司用一些線上的轉短地址網站,但出來的的地址輸入沒規則,輸入太麻煩了,而且掃碼還需要安裝一個掃碼的軟體,在一個就是不能轉換本地代理的地址(例: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
- 重啟電腦測試~~~