教你做一个永久不失效的自己域名的私有短链

最近总是推广些网站什么的,一般的网站推广都是域名+邀请码,但是很多聪明人总是把我的邀请码去掉。。。
网上的各种免费短链什么的各种广告,还时不时就失效。
所以,自己搞个域名重定向不就可以了么。

首先阿里云搞个99一年的服务器(我有其他业务在跑,如果只要个短链可以参考函数计算几乎免费)
服务器中部署的话先安装python环境,然后cmd中执行

pip install flask

然后新建一个文本文档,复制下面的重定向代码进去,改好自己的地址,然后文本文档后缀txt改成py,双击运行,因为服务器中还涉及端口安全组那些东西,新手玩家没有其他业务的话就不要搞了。

函数计算操作如下:
首先点击这个函数及服务
在这里插入图片描述
创建服务,随便写个名称,日志禁用(不禁用的话会有日志费用产生哦)
在这里插入图片描述
点击创建函数在这里插入图片描述
依次按图选,名字随便写
在这里插入图片描述
高级配置这里这么改
在这里插入图片描述
触发器这里选择无认证
在这里插入图片描述

然后点下面的这个确定
之后会跳转到代码窗口页面
在这里插入图片描述
这个index.py就是运行的代码文件了,右侧的代码内容全选,删除
然后替换重定向的代码上去

# 重定向代码:
from flask import Flask,redirect


REQUEST_ID_HEADER = 'x-fc-request-id'

app = Flask(__name__)

fixed_url = "https://university.aliyun.com/mobile?userCode=s8cs0rpo"

@app.route('/')
def redirect_to_fixed_url():
    # 当访问此路由时,将用户重定向到预设的 URL
    return redirect(fixed_url, code=302)

if __name__ == '__main__':
        app.run(host='0.0.0.0',port=9000)

在这个代码中fixed_url 就是你实际要跳转的地址了,之后改这个地址就可以。
在这里插入图片描述
点击左下角那个位置,然后弹出的黑框中选择TERMINAL,在光标位置输入

pip install flask -t .

然后回车
在这里插入图片描述
现在你的页面应该是这样,然后点击上面的部署。
在这里插入图片描述
之后点击上面的触发器管理
在这里插入图片描述
点击这个自定义域名(前提阿里云买个喜欢的域名,然后备案,个人备案就可以)
在这里插入图片描述
点击添加自定义域名
在这里插入图片描述

先填写域名名称,按照你自己的域名写,前缀可以随便起,例如我的域名xytx.space,这次做的阿里云的跳转,我就起个aliyun.xytx.space,然后下面依次选择你的服务、函数名这些,然后点击确定。
在这里插入图片描述
这时候会弹出失败,不用担心,下面有个自动按钮,点一下
在这里插入图片描述
然后再次点击确定,就成功创建了
现在这个位置就可以看到设置的自定义域名了
在这里插入图片描述
访问一下试试
就会发现访问的事aliyun.xytx.space实际页面显示的是阿里云的界面了
在这里插入图片描述

<think>好的,我现在需要帮用户用Gin框架写一个生成系统的后端部分,并且使用雪花算法生成分布式唯一ID。首先,我得理清楚用户的需求是什么。他们需要的是一个后端服务,能够接收原始URL,生成对应的,并且存储起来,当访问时重定向到原始URL。同时,要确保生成的ID在分布式环境下是唯一的,所以需要用到雪花算法。 首先,我得回忆一下Gin框架的基本用法。Gin是一个高性能的HTTP框架,用Go语言写的,路由和中间件的处理都很方便。接下来是雪花算法的实现,我需要确认雪花算法的结构,通常包括时间戳、机器ID、序列号等部分,确保在分布式系统中生成唯一ID。 然后,考虑项目的结构。通常一个Gin项目会有main.go作为入口,定义路由和启动服务。可能还需要一个单独的包来处理雪花算法,比如snowflake,里面实现ID生成逻辑。另外,数据存储部分,用户可能暂时需要数据库,但为了持久化,可能需要使用内存存储或者文件存储,过根据用户的要求,可能先用内存存储,方便演示。 接下来是路由设计。用户需要两个主要的端点:一个用于创建(POST请求),另一个用于重定向(GET请求)。例如,POST /api/shorten 接收原始URL,返回;GET /:shortID 根据重定向到原始URL。 然后考虑数据存储结构。可以用一个map来存储ID到原始URL的映射,这样查找起来快速。过要注意并发安全,因为Gin处理请求是并发的,所以需要使用sync.Map或者加锁机制。过sync.Map可能在性能上更好,特别是在读多写少的情况下。 雪花算法的实现是关键。需要确保每个实例的机器ID同,否则可能生成重复ID。通常雪花算法中的机器ID需要配置,或者通过某种方式自动获取,比如环境变量。这里可能需要用户自行配置,或者通过其他方式确保同实例的机器ID同,比如使用Kubernetes的Pod ID或者IP地址的一部分。但在示例中,可能先写死或者通过环境变量传入。 接下来是的生成。雪花算法生成的ID是int64,需要将其转换为更的字符串,比如Base62编码,这样比Base64更友好,没有特殊字符。Base62编码可以使用数字和大小写字母,缩字符串长度。例如,一个int64的ID转换为Base62后大概是11位字符,取决于具体数值。 然后是处理流程。当用户POST一个原始URL时,生成雪花ID,转换为字符串,存储到map中,然后返回。当用户访问时,查找map中对应的原始URL,返回302重定向。 还需要处理可能的错误,比如URL格式正确,或者存在的情况。Gin提供了方便的返回JSON和状态码的方法,可以在这里使用。 现在需要测试代码的正确性。比如,生成ID是否唯一,转换后的是否正确,重定向是否正常工作。可能需要写单元测试,但用户可能只需要示例代码,所以可以暂时省略测试部分。 最后,考虑部署和配置。比如机器ID如何设置,是否需要环境变量,或者配置文件。在示例中,可能需要从环境变量读取,或者默认一个值,但提醒用户在生产环境中需要正确配置。 可能遇到的问题包括:雪花算法的时间回拨问题,如何处理?通常雪花算法实现需要考虑这种情况,比如等待时间追上或者抛出异常。但示例中可能暂时处理,假设时间正常。另外,的存储如果重启会丢失,所以用户可能需要持久化存储,但根据当前需求,可能只需要内存存储,用户可以根据需要扩展。 总结步骤: 1. 实现雪花算法生成唯一ID。 2. 创建Gin路由,处理POST和GET请求。 3. 使用Base62将ID转换为字符串。 4. 使用并发安全的数据结构存储映射。 5. 处理错误和重定向。 现在需要将这些步骤转化为代码,确保每个部分都正确,并且有必要的注释,方便用户理解。同时,用户可能需要知道如何运行和测试,比如使用curl命令测试API。</think>我将以模块化方式为您构建基于Gin的系统,包含分布式ID生成和核心功能实现: 一、项目结构 ``` shorturl/ ├── main.go # 入口文件 ├── go.mod ├── handler/ # 业务处理 │ └── shorten.go ├── pkg/ │ ├── snowflake/ # 雪花算法实现 │ │ └── id_gen.go │ └── base62/ # 进制转换 │ └── encode.go └── storage/ # 存储抽象 └── memory.go ``` 二、核心代码实现 1. 雪花算法实现 (`pkg/snowflake/id_gen.go`) ```go package snowflake import ( "sync" "time" ) const ( epoch = 1640995200000 // 2022-01-01 00:00:00 UTC machineIDBits = 10 sequenceBits = 12 maxMachineID = -1 ^ (-1 << machineIDBits) ) type IDGenerator struct { machineID int sequence int lastStamp int64 mu sync.Mutex } func New(machineID int) *IDGenerator { if machineID < 0 || machineID > maxMachineID { panic("invalid machine ID") } return &IDGenerator{machineID: machineID} } func (g *IDGenerator) Generate() int64 { g.mu.Lock() defer g.mu.Unlock() now := time.Now().UnixNano() / 1e6 if now < g.lastStamp { panic("clock moved backwards") } if now == g.lastStamp { g.sequence = (g.sequence + 1) & ((1 << sequenceBits) - 1) if g.sequence == 0 { for now <= g.lastStamp { now = time.Now().UnixNano() / 1e6 } } } else { g.sequence = 0 } g.lastStamp = now return ((now - epoch) << (machineIDBits + sequenceBits)) | (int64(g.machineID) << sequenceBits) | int64(g.sequence) } ``` 2. Base62编码 (`pkg/base62/encode.go`) ```go package base62 const charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" func Encode(n int64) string { if n == 0 { return string(charset[0]) } var result []byte for n > 0 { result = append(result, charset[n%62]) n /= 62 } // 反转数组 for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 { result[i], result[j] = result[j], result[i] } return string(result) } ``` 3. 存储实现 (`storage/memory.go`) ```go package storage import "sync" type MemoryStorage struct { mu sync.RWMutex store map[string]string } func NewMemoryStorage() *MemoryStorage { return &MemoryStorage{ store: make(map[string]string), } } func (s *MemoryStorage) Save(shortURL, originalURL string) { s.mu.Lock() defer s.mu.Unlock() s.store[shortURL] = originalURL } func (s *MemoryStorage) Get(shortURL string) (string, bool) { s.mu.RLock() defer s.mu.RUnlock() val, exists := s.store[shortURL] return val, exists } ``` 4. 主逻辑 (`main.go`) ```go package main import ( "net/http" "os" "shorturl/pkg/base62" "shorturl/pkg/snowflake" "shorturl/storage" "github.com/gin-gonic/gin" ) var ( idGen *snowflake.IDGenerator store *storage.MemoryStorage ) func init() { // 从环境变量获取机器ID,默认0 machineID := 0 if envID := os.Getenv("MACHINE_ID"); envID != "" { machineID = // 添加转换逻辑 } idGen = snowflake.New(machineID) store = storage.NewMemoryStorage() } func main() { r := gin.Default() r.POST("/shorten", func(c *gin.Context) { type request struct { URL string `json:"url" binding:"required,url"` } var req request if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": "invalid URL"}) return } // 生成唯一ID id := idGen.Generate() shortKey := base62.Encode(id) // 存储映射关系 store.Save(shortKey, req.URL) c.JSON(http.StatusOK, gin.H{ "short_url": "http://localhost:8080/" + shortKey, }) }) r.GET("/:key", func(c *gin.Context) { key := c.Param("key") if original, exists := store.Get(key); exists { c.Redirect(http.StatusMovedPermanently, original) return } c.JSON(http.StatusNotFound, gin.H{"error": "URL not found"}) }) r.Run(":8080") } ``` 三、运行与测试 1. 启动服务: ```bash export MACHINE_ID=1 # 同节点设置同ID go run main.go ``` 2. 测试请求: ```bash # 生成 curl -X POST http://localhost:8080/shorten \ -H "Content-Type: application/json" \ -d '{"url":"https://www.example.com/some/long/url"}' # 访问 curl -v http://localhost:8080/Abc123 ``` 四、系统优化方向 1. 性能提升: $$ \text{QPS} = \frac{\text{可用连接数}}{\text{平均响应时间}} $$ - 添加Redis缓存层 - 使用连接池 2. 扩展功能: ```go // 添加过期时间 type URLRecord struct { Original string ExpireAt time.Time } // 定时清理任务 func startCleanupTask() { ticker := time.NewTicker(1 * time.Hour) go func() { for range ticker.C { // 清理过期记录 } }() } ``` 3. 监控指标: - 使用Prometheus监控接口成功率 $$ \text{成功率} = \frac{\text{成功请求数}}{\text{总请求数}} \times 100\% $$ 需要补充实现分布式锁机制或数据库持久化存储方案吗?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小袁同学.

赏个早餐吃?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值