使用它作為短網址產生可以嗎?-Hashids.net

使用它作為短網址產生可以嗎?-Hashids.net

Hashids.net是一款輕量級開源的將數字編碼成字串的加密(短ID產生)工具類別庫,其實靈活運用它將字串產生短Id也是可以的,只是不可逆。

最後更新 2023/9/17 下午8:31
Rector
預計閱讀 10 分鐘
分類
.NET
標籤
.NET C# 開源

概述

本文為 .NET 開發者們分享一款輕量級開源的將數字編碼成字串的加密(短 ID 產生)工具類別庫—Hashids.net

無論在前端還是後端的程式開發中,都會遇到讓系統自動產生一些編碼或 ID 的場景,並且要求產生的編碼或 ID 是不重複的(重複率極低的)。

前端開發中,常用的有 nanoid。而後端開發中,常用的技術則有:自增 ID、雪花 ID、GUID 等。其中,自增 ID 在中小型系統中使用比較常見,它佔用的儲存空間相對較小,檢索速度相對較快,但它不適用於分散式系統的建置;而雪花 ID 和 GUID 等佔用位元組較多,佔用儲存空間較大,檢索速度相對較慢,但後兩者適用於分散式系統的建置。

另外,還有一些場景,為了隱藏後端的真實 ID,在顯示到客戶端時,對真實 ID 進行加密處理,將真實的數字加密產生一個短字串,例如國外知名影片網站油管的影片位址類似 https://www.yt.com/watch?v=yVd7vbeFj-g,其中的參數 v 的值 yVd7vbeFj-g 即為一個加密的字串。

在 .NET、.NET Core、.NET 5\6\7\8 等程式開發中,如果你也想產生類似的加密字串,本文為 .NET 開發者們推薦 Hashids.net 這個開源的短 ID 產生(加密)類別庫。

Hashids.net 功能和特性

Hashids.net 可以將數字轉換成字串,例如將 347 轉換成 yr8,或將數字陣列 [27, 986] 轉換成 3kTMd。當然,你也可以將轉換後的字串再次轉換成數字或數字陣列。這在將多個參數捆綁成一個參數、隱藏實際 ID 或簡單地將它們用作短字串 ID 時非常有用。

Hashids.net 主要有如下的特性:

  • 將整數轉換成唯一的短 ID(僅支援包含零在內的正整數)
  • 為自增 ID 產生不可推測的非連續 id
  • 支援單個數字或數字陣列
  • 允許自訂字母和鹽
  • 允許指定最小雜湊長度

Hashids.net 的安裝

Hashid.net 以 NuGet 套件發布,所以有如下的安裝方式:

1.NuGet 指令行

Install-Package Hashids.net

2.NuGet 套件管理工具

在專案中右鍵按一下相依項,如圖:

然後,在開啟的 NuGet 套件管理介面輸入關鍵字 Hashids.net,在搜尋到的結果中選中 Hashids.net 類別庫元件並安裝,如圖:

Hashids.net 的使用

匯入 Hashids.net 的命名空間

using HashidsNet;

編碼單個數字

實例化 Hashids 物件時,你可以傳遞一個唯一的鹽值,這樣你的雜湊值就不同於其他人的雜湊值。這裡使用 this is my salt 作為例子。

var Hashids = new Hashids("this is my salt");
var hash = hashids.Encode(12345);

執行結果為:NkK9

如果要轉換一個 Int64 類型的數字,則需要呼叫 EncodeLong() 方法,如下:

var hashids = new Hashids("this is my salt");
var hash = hashids.EncodeLong(666555444333222L);

執行結果為:KVO9yy1oO5j

解碼

Hashids.net 提供了將已編碼的字串反解碼的功能,但解碼時需使用與編碼相同的鹽值:

var hashids = new Hashids("this is my salt");
numbers = hashids.Decode("NkK9");

執行結果為:[ 12345 ]

var hashids = new Hashids("this is my salt");
numbers = hashids.DecodeLong("KVO9yy1oO5j");

執行結果為:[ 666555444333222L ]

使用不同的鹽值解碼

如果解碼時的鹽值與編碼時不相同,則解碼將失敗:

var hashids = new Hashids("this is my pepper");
numbers = hashids.Decode("NkK9");

執行結果為:[]

編碼多個數字

var hashids = new Hashids("this is my salt");
var hash = hashids.Encode(683, 94108, 123, 5);

執行結果為:aBMswoO2UB3Sj

多個數字編碼後的解碼

var hashids = new Hashids("this is my salt");
var numbers = hashids.Decode("aBMswoO2UB3Sj")

執行結果為:[ 683, 94108, 123, 5 ]

指定編碼後的最小雜湊長度

以下範例將對整數 1 進行編碼,並將最小雜湊長度設定為 8(預設情況下是 0——這表示雜湊將是可能的最短長度)。

var hashids = new Hashids("this is my salt", 8);
var hash = hashids.Encode(1);

執行結果為:gB0NV05e

解碼

var hashids = new Hashids("this is my salt", 8);
var numbers = hashids.Decode("gB0NV05e");

執行結果為:[ 1 ]

自訂雜湊字母

以下範例指定了自訂的雜湊字母為 abcdefghijkABCDEFGHIJK12345

var hashids = new Hashids("this is my salt", 0, "abcdefghijkABCDEFGHIJK12345")
var hash = hashids.Encode(1, 2, 3, 4, 5)

執行結果為:Ec4iEHeF3

Hashids.net 的隨機性

Hashids.net 的主要目的是混淆 ID,此外,它還可以讓有規律的數字變得不可猜測和不可預測。

編碼重複的數字

var hashids = new Hashids("this is my salt");
var hash = hashids.Encode(5, 5, 5, 5);

編碼後,你不會看到任何重複的模式來表明雜湊中有 4 個相同的數字,執行結果為:1Wc8cwcE

編碼有序的數字

var hashids = new Hashids("this is my salt");
var hash = hashids.Encode(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

執行結果為:kRHnurhptKcjIDTWC3sx

編碼自增的數字

var hashids = new Hashids("this is my salt");

hashids.Encode(1); // => NV
hashids.Encode(2); // => 6m
hashids.Encode(3); // => yD
hashids.Encode(4); // => 2l
hashids.Encode(5); // => rD

編碼十六進位

var hashids = new Hashids("this is my salt");
var hash = hashids.EncodeHex("DEADBEEF");

執行結果為:kRNrpKlJ

解碼十六進位

var hashids = new Hashids("this is my salt");
var hex = hashids.DecodeHex("kRNrpKlJ");

執行結果為:DEADBEEF

將字串加密產生短字串怎樣?

以下為站長擴充長字串轉短字串方法介紹

其實很簡單,將需要加密的原字串作為鹽,加密數字固定,這樣就簡單實現了:

public static string GetHashids(this string sourceStr, int number = 9)
{
    var hashids = new Hashids(sourceStr);
    return hashids.Encode(number);
}

單元測試如下:例如將本文別名【Is-it-possible-to-use-it-as-a-short-link-generator-Hashidsnet】加密

[TestClass]
public class HashHelperUnitTest
{
    [TestMethod]
    public void Hashids_Success()
    {
        var blogPostSlugStr = "Is-it-possible-to-use-it-as-a-short-link-generator-Hashidsnet";

        var encodeStr1 = blogPostSlugStr.GetHashids();
        var encodeStr2 = blogPostSlugStr.GetHashids();

        Assert.AreEqual(encodeStr1, encodeStr2);
    }
}

別名加密後為:【6Q】,可打開瀏覽器訪問本文短連結位址嘗試:https://dotnet9.com/6Q 。

註:這樣使用不是本庫的初衷,但將長字串轉成短字串這確不失為一種好想法,哈哈,記住這不可逆哈。

小知識

將一個長字串轉成短字串有多種方法可實現,常規做法:

  1. 使用資料庫儲存短字串和原字串,短字串可自行定義規則,例如從 1 開始取值,每次取值時讀資料庫,根據短字串取長字串或根據長字串取短字串。

優點:短字串與原字串一一對應,可以實現雙向轉換,不會出現重複的短字串。

缺點:需要頻繁讀寫資料庫,對資料庫的效能有一定的影響。

  1. 將長字串使用一種演算法轉成短字串,有演算法是可逆的,有的是不可逆的。

無需資料庫儲存,但長度可能會略長。

  • 可逆演算法範例(C#):
public static string ShortenString(string longString)
{
    byte[] bytes = Encoding.UTF8.GetBytes(longString);
    string shortString = Convert.ToBase64String(bytes);
    return shortString;
}

public static string RestoreString(string shortString)
{
    byte[] bytes = Convert.FromBase64String(shortString);
    string longString = Encoding.UTF8.GetString(bytes);
    return longString;
}
  • 不可逆演算法範例(C#):
public static string ShortenString(string longString)
{
    using (SHA256 sha256 = SHA256.Create())
    {
        byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(longString));
        string shortString = Convert.ToBase64String(hashBytes);
        return shortString;
    }
}
  • 區別:
    • 可逆演算法可以透過短字串還原為原字串,而不可逆演算法無法還原。
    • 可逆演算法產生的短字串長度較長,而不可逆演算法產生的短字串長度較短。
    • 使用演算法自動產生短字串無需頻繁讀寫資料庫,效能較好,但可能存在短字串衝突的問題,即不同的長字串可能產生相同的短字串。

最後列出完整的單元測試希望對您有用:

using HashidsNet;
using System.Security.Cryptography;
using System.Text;

namespace Dotnet9.Commons.Test;

[TestClass]
public class HashHelperUnitTest
{
    public static string GetHashids(string sourceStr, int number = 9)
    {
        var hashids = new Hashids(sourceStr);
        return hashids.Encode(number);
    }

    [TestMethod]
    public void Hashids_Success()
    {
        var blogPostSlugStr = "Is-it-possible-to-use-it-as-a-short-link-generator-Hashidsnet";

        var encodeStr1 = GetHashids(blogPostSlugStr);
        var encodeStr2 = GetHashids(blogPostSlugStr);

        Assert.AreEqual(encodeStr1, encodeStr2);
    }


    [TestMethod]
    public void Hashids_Best_Success()
    {
        var blogPostSlugStr = "Is-it-possible-to-use-it-as-a-short-link-generator-Hashidsnet";

        var encodeStr1 = blogPostSlugStr.GetHashids();
        var encodeStr2 = ShortenString(blogPostSlugStr);
        var encodeStr3 = ShortenString2(blogPostSlugStr);

        Assert.IsTrue(encodeStr1.Length < encodeStr2.Length, "Hashids產生的短字串比Base64還短");

        Assert.IsTrue(encodeStr1.Length < encodeStr3.Length, "Hashids產生的短字串還是短那麼一點點");
    }

    public static string ShortenString(string longString)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(longString);
        string shortString = Convert.ToBase64String(bytes);
        return shortString;
    }

    public static string RestoreString(string shortString)
    {
        byte[] bytes = Convert.FromBase64String(shortString);
        string longString = Encoding.UTF8.GetString(bytes);
        return longString;
    }

    public static string ShortenString2(string longString)
    {
        using (SHA256 sha256 = SHA256.Create())
        {
            byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(longString));
            string shortString = Convert.ToBase64String(hashBytes);
            return shortString;
        }
    }
}

本文大部分引用知乎原文章:

原文標題:分享.NET/.NET 5 輕量級開源的將數字編碼成字串的加密(短 ID 產生)工具類別庫--hashids.net

原文連結:https://codedefault.com/p/lightweight-open-source-project-hashids-net-for-generating-short-ids-from-numbers

繼續探索

延伸閱讀

更多文章
同分類 / 同標籤 2026/2/7

AOT使用經驗總結

從專案建立伊始,就應養成良好的習慣,即只要添加了新功能或使用了較新的語法,就及時進行 AOT 發布測試。

繼續閱讀