首页 > 编程语言 >使用Go语言开发一个短链接服务:四、生成code算法

使用Go语言开发一个短链接服务:四、生成code算法

时间:2024-03-26 12:12:45浏览次数:15  
标签:code letters unsafe 生成 Go 链接

章节

使用Go语言开发一个短链接服务:一、基本原理  

使用Go语言开发一个短链接服务:二、架构设计

使用Go语言开发一个短链接服务:三、项目目录结构设计

使用Go语言开发一个短链接服务:四、生成code算法

使用Go语言开发一个短链接服务:五、添加和获取短链接

使用Go语言开发一个短链接服务:六、链接跳转

  源码:https://gitee.com/alxps/short_link

 

  上一篇介绍了项目目录接口,这篇将实现短链接code算法。

 

前言

  假如某个用户,有个长链接为:https://github.com/gin-gonic/gin/blob/master/internal/bytesconv/bytesconv_1.19.go,我们短链接服务域名为https://a.b.c,为这个长链接生成对应的短链接为https://a.b.c/N26jas。这里code便是Na6jas。

  code必须满足以下几个要求:

    1、只包含,大小写字母或数字

    2、短

    3、唯一

  大小字母加上数字,共62个,当code长度为N时,code可以有62的N次方个。N为5、6、7,code个数大约为1600万, 568亿, 3.5万亿。586亿够用,因此系统code长度为6,够短。

 

如何生成唯一code

  这还不简单!生成6位随机大小写字母或数字的字符,数据库存在,重新随机生成,递归直到不冲突。本篇完……,当然不是。

  至于如何生成6位随机大小写字母或数字,可以看看这篇文章:Golang 生成随机字符串的八种方式与性能测试。文章随机字符串只有大小写字母,我们在此基础上稍作修改,代码如下:

package service

import (
	"math/rand"
	"time"
	"unsafe"
)

const letters = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

var src = rand.NewSource(time.Now().UnixNano())

const (
	// 6 bits to represent a character index
	charIdBits = 6
	// All 1-bits as many as charIdBits
	charIdMask = 1<<charIdBits - 1
	// 由于现在包含了62个字符,计算新的charIdMax
	charIdMax = 63 / charIdBits
	// 字符集的大小
	charsetSize = len(letters)
)

func randStr(n int) string {
	b := make([]byte, n)
	for i, cache, remain := n-1, src.Int63(), charIdMax; i >= 0; {
		if remain == 0 {
			cache, remain = src.Int63(), charIdMax
		}
		if idx := int(cache & charIdMask); idx < charsetSize {
			b[i] = letters[idx]
			i--
		}
		cache >>= charIdBits
		remain--
	}
	return unsafe.String(unsafe.SliceData(b), len(b))
}

   但是,我想法是,code要根据用户id和长链接url推算出来,即相同的user_id+long_url,每次得到的code都一样。先上代码,再讲思路

package service

import (
	"crypto/md5"
	"encoding/hex"
	"hash/fnv"
	"io"
	"unsafe"

	"github.com/1911860538/short_link/config"
)

const letters = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

var confCodeLen = config.Conf.Core.CodeLen

// GenCode
func GenCode(userId string, longUlr string, salt string) (string, error) {
	// 首先对userId+longUrl+salt md5 主要为了防止longUrl包含汉字等字符串
	hasher := md5.New()
	if _, err := io.WriteString(hasher, userId+longUlr+salt); err != nil {
		return "", err
	}
	hashStr := hex.EncodeToString(hasher.Sum(nil))

	stepLen := len(hashStr) / confCodeLen
	remain := len(hashStr) % confCodeLen
	if remain > 0 {
		stepLen += 1
	}
	lettersLen := uint32(len(letters))
	b := make([]byte, confCodeLen)

	for i := 0; i < confCodeLen; i++ {
		// 根据要生成的code长度,切分md5字符串
		var piece string
		if remain > 0 && i == confCodeLen-1 {
			piece = hashStr[i*stepLen : i*stepLen+remain]
		} else {
			piece = hashStr[i*stepLen : i*stepLen+stepLen]
		}

		// 为切片元素生成对应的整形数值
		h := fnv.New32a()
		pieceBytes := unsafe.Slice(unsafe.StringData(piece), len(piece))
		if _, err := h.Write(pieceBytes); err != nil {
			return "", err
		}
		pieceHash32 := h.Sum32()

		// 切片字符的整形,取len(letters)余数,并取letters索引为该余数的letter
		letterIdx := pieceHash32 % lettersLen
		b[i] = letters[letterIdx]
	}

	return unsafe.String(unsafe.SliceData(b), len(b)), nil
}

  比如user_id为"1f70a466-1449-4676-b2d7-2037341c718e",long_url为"https://i.cnblogs.com/posts/edit;postId=18090256":

    1、将user_id+long_url字符串,生成md5的哈希字符串,这一步是为了得到固定长度的字符。结果为,"101360eb993b977d9f6969813ee84338"

    2、根据要生成的code长度,切分步骤1的字符串。我们要得到6位code,因而我们将得到的字符切片结果为,["101360", "eb993b", "977d9f", "696981", "3ee843", "38"]

    3、接着我们对步骤2每个字符切片元素,使用fnv哈希,获得uint32,结果为[791694210, 3988549581, 2254501405, 2706880430, 3291227237, 2414894606]

    4、对步骤3,uint32切片,每个元素,取letters长度余数,获得余数切片,[28, 53, 55, 48, 17, 0]

    5、取letters索引为步骤4余数切片的字母或数字字符,得到最终结果,"2RTMra"

  步骤3/4参考了一致性哈希。当然,上面两种获取6位code方式凭个人想法哈,网上也有其它算法实现可参考。本项目中使用上面说的后者。

 

总结

  本篇讲了短链接code生成逻辑,下一篇讲添加和获取短链接逻辑。

标签:code,letters,unsafe,生成,Go,链接
From: https://www.cnblogs.com/ALXPS/p/18090256

相关文章

  • 使用Go语言开发一个短链接服务:五、添加和获取短链接
    章节 使用Go语言开发一个短链接服务:一、基本原理 使用Go语言开发一个短链接服务:二、架构设计 使用Go语言开发一个短链接服务:三、项目目录结构设计 使用Go语言开发一个短链接服务:四、生成code算法 使用Go语言开发一个短链接服务:五、添加和获取短链接 使用Go语言开......
  • 使用Go语言开发一个短链接服务:六、链接跳转
    章节 使用Go语言开发一个短链接服务:一、基本原理 使用Go语言开发一个短链接服务:二、架构设计 使用Go语言开发一个短链接服务:三、项目目录结构设计 使用Go语言开发一个短链接服务:四、生成code算法 使用Go语言开发一个短链接服务:五、添加和获取短链接 使用Go语言开......
  • 使用Go语言开发一个短链接服务:三、项目目录结构设计
    章节 使用Go语言开发一个短链接服务:一、基本原理 使用Go语言开发一个短链接服务:二、架构设计 使用Go语言开发一个短链接服务:三、项目目录结构设计 使用Go语言开发一个短链接服务:四、生成code算法 使用Go语言开发一个短链接服务:五、添加和获取短链接 使用Go语言开......
  • SuccessFactors的岗位code必须是8位的数字
    今天遇到岗位的code居然维护中文,顿时傻眼,SuccessFactors的code可以是数字,但是SAP的id是8位的数字,所以传输到SAP系统后报错。后来发现sf可以做正则表达式:控制岗位code必须是8位的数字......
  • golang模板库之fasttemplate
    简介fasttemplate是一个比较简单、易用的小型模板库。fasttemplate的作者valyala另外还开源了不少优秀的库,如大名鼎鼎的fasthttp,前面介绍的bytebufferpool,还有一个重量级的模板库quicktemplate。quicktemplate比标准库中的text/template和html/template要灵活和易用很多,后面会专......
  • Go的可变参数函数
    可变函数是指可以接收可变数量的参数的函数。在Golang中,可以传递与函数签名中引用的类型相同的不同数量的参数。在声明可变函数时,最后一个参数的类型前会有一个省略号"...",这表明该函数可以用任意数量的该类型参数来调用,可以是0个、1个或者多个。这种类型的函数在不知道传递给......
  • Django之权限管理
    一,引入1.为什么要有权限?2.为什么要开发权限的组件?3.在web开发中,什么是权限?4.表结构的设计权限表IDURL1/user_list/2/customer_list/用户表IDUSER_NAME1root2root2角色/用户组表ID组1销售2开发用户与角色的......
  • CPPB 表中的TXN_CATEGORY
    cst_pac_period_balanceTXN_CATEGORY1    期初    2    成本更新:新成本或百分比变动    3    自有成本事务处理    4    非返工完成    5    成本更新:值变动    6    返工发放    7    返工完成    8    组......
  • 强大的VS插件CodeRush全新发布v23.2.6——支持语音
    CodeRush是一个强大的VisualStudio.NET插件,它利用整合技术,通过促进开发者和团队效率来提升开发者体验。CodeRushv23.2.6正式版下载具体更新详情如下:语音支持-CTP指定Azure语音识别和OpenAIAPI密钥后,可以在VisualStudio2022中启用语音功能。语音命令按住Ctrl键并说......
  • google搜索如何修改搜索结果地区
    本文写于2024年03月25日,阅读时请注意时效。解决使用谷歌搜索引擎的时候经常会因为IP地址位置导致搜索结果的语言出现偏差,尤其是使用汉语进行搜索时常常会导致搜索结果中出现很多日语等语言结果造成干扰的问题。设置位置在:首页→右下角Settings→Searchsettings→左上角......