1. 程式人生 > >Nodejs+mySql實現長地址轉短地址

Nodejs+mySql實現長地址轉短地址

XP 域名 length character 重啟 into head val 下載

一、開發原因

  之前公司用一些在線的轉短地址網站,但出來的的地址輸入沒規則,輸入太麻煩了,而且掃碼還需要安裝一個掃碼的軟件,在一個就是不能轉換本地代理的地址(例:http://192.168.1.200:8080),心累。正好公司有個閑置的電腦做服務器,想著幹嘛不搞個本地的轉短地址工具,這樣可以隨意設置,想咋弄就咋弄。

  註:這個插件沒有部署到服務器上,只是在本地搭建了一個可運行環境,在局域網內可以隨意訪問。不過只要部署到服務器,再給個域名,就完全可以用,童鞋們可以自行補全。

二、開發環境

  1. 系統環境:macOS, Version 10.13.1
  2. nodejs (v9.2.0)  後臺語言
  3. mysql (v5.7.17)  數據庫
  4. MySQLWorkbench (v6.3.10)  數據庫可視化工具
  5. Chrome Extension  Chrome插件

三、分析開發流程

  1. 獲取長鏈接地址
  2. 把地址傳給後臺
  3. 查找數據庫裏面是否存在改地址
  4. 生成短地址
  5. 返回短地址數據

四、開發流程

 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 })

五、啟動方式

  1. 添加Chrome插件到Chrome瀏覽器
  2. 在命令行定位到項目工程文件
  3. 運行node app命令開啟本地服務
  4. 找一個地址,點擊那個插件生成短地址測試
  5. 完成

六、結果截圖

技術分享圖片

    親測有效~~~

七、遷移到Windows服務器

  1. 系統環境:win7系統(32位)------ 一臉懵逼的吐槽公司這臺閑置的電腦,這配置~~~
  2. nodejs (v8.11.2)  後臺語言 ------ 直接下載msi文件點擊安裝
  3. mysql (v8.....忘記了)  數據庫 ------ 下載msi文件跟著步驟安裝
  4. MySQLWorkbench (v6.3.10)  數據庫可視化工具
  5. 再次吐槽一下這臺電腦,.Net Framework版本低的不要不要的,mySql軟件需要的環境都要升級,折騰一下午終於搞定,至於配置方式可以百度解決
  6. Windows有個好處就是可以設置開機運行腳本,這樣每次啟動就可以自動開啟服務了,不需要每次手動去開。
  7. 新建一個txt文件,裏面輸入node C:\url\app(因為我把工程文件就放在了c盤下面),如果路徑不同可以自行調整
  8. 保存txt文件,然後把文件後綴改成bat,然後添加到開機啟動項裏面,這裏推薦一篇關於設置啟動項的文章:http://blog.51cto.com/10676568/1974842
  9. 重啟電腦測試~~~

Nodejs+mySql實現長地址轉短地址