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

来源:https://www.cnblogs.com/lawliet-qiu/archive/2018/06/01/9123185.html
-Advertisement-
Play Games

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


一、開發原因

  之前公司用一些線上的轉短地址網站,但出來的的地址輸入沒規則,輸入太麻煩了,而且掃碼還需要安裝一個掃碼的軟體,在一個就是不能轉換本地代理的地址(例: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. 重啟電腦測試~~~

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一. DML觸發器; 二. DDL觸發器; 三. LOGON 觸發器; ...
  • 一、資料庫簡介 資料庫概述 資料庫(database)是按照數據結構來組織,存儲和管理數據的倉庫,它產生與距今五十年前. 簡單來說是本身可視為電子化的文件櫃--存儲電子文件的處所,用戶可以對文件中的數據運行新增,截取,更新,刪除等操作。 常見的數據模型 1. 層次結構模型:層次結構模型實質上是一種有 ...
  • ProGuard介紹 ProGuard是一個Java類文件壓縮器,優化器,混淆器和預先文件驗證器。 壓縮步驟檢測和刪除未使用的類,欄位,方法和屬性。 優化步驟分析和優化方法的位元組碼。 混淆步驟使用短無意義的名稱重命名剩餘的類,欄位和方法。 這些步驟使代碼更小,更高效,更難以進行逆向工程。 最終的預驗 ...
  • 1、標準廣播:是一種完全非同步執行的廣播,在廣播發出之後,所有的廣播接收器幾乎會在同一時刻接收到這條廣播信息,它們之間沒有先後順序。效率高、無法被截斷。 2、有序廣播:是一種同步執行的廣播,在廣播發出後,同一時刻只會有一個廣播接收器能夠接收到這條廣播,當這個廣播接收器中的邏輯執行完畢後,廣播才會繼續傳 ...
  • #define KColorRandomColor [UIColor colorWithRed:arc4random()%255/255.0 green:arc4random()%255/255.0 blue:arc4random()%255/255.0 alpha:1.0] ...
  • 卸載手機上的相應APP即可 ...
  • 一,新建立一個工程,Hello,如圖所示。 二,Xcode >New >File >FirstViewController >選中Also create XIB file >Next.如圖所示。 三,如下圖所示。 四,在AppDelegate.m中輸入如下代碼 : 五,在FristViewContr ...
  • 關於ajax的名字 ajax 的全稱是Asynchronous JavaScript and XML,其中,Asynchronous 是非同步的意思,它有別於傳統web開發中採用的同步的方式。 關於同步和非同步 非同步傳輸是面向字元的傳輸,它的單位是字元;而同步傳輸是面向比特的傳輸,它的單位是楨,它傳輸的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...