介绍

一个基于Python-Flask框架开发的短网址生成器,数据库使用python内置的Sqlite3,直接部署即可使用,不需额外再创建数据库。同时提供短网址生成API与心灵毒鸡汤API。

短网址生成器

[btn class="btn-info btn-rounded" url="https://surl.ztyang.com"]点击预览[/btn]

GitHub地址: https://github.com/ztyangt/shorturl

原理

简述

所谓短网址生成,并不是真正意义上的将长长的URL给变短了,它只不过是为长链接生成一个专属的短链,当我们在浏览器里访问这个短链时,再302重定向到原来的长链接。

意义:

  1. 易于传播,易于记住
  2. 生成的二维码较原链接简单
  3. 等等...

基于Flask实现

Flask是一个轻量级的可定制框架,使用Python语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。它可以很好地结合MVC模式进行开发,开发人员分工合作,小型团队在短时间内就可以完成功能丰富的中小型网站或Web服务的实现。另外,Flask还有很强的定制性,用户可以根据自己的需求来添加相应的功能,在保持核心功能简单的同时实现功能的丰富与扩展,其强大的插件库可以让用户实现个性化的网站定制,开发出功能强大的网站。

数据库初始化

class initDB(object):
    def __init__(self, app=None):
        if app:
            self.init_app(app)

    def init_app(self, app):
        DB = SqlHelper.Connect(DB_FILE_PATH)
        DB.table('shortURL').create({
            'id': 'INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT',
            'shortID': 'TEXT NOT NULL',
            'longUrl': 'TEXT NOT NULL',
            'shortUrl': 'TEXT NOT NULL',
            'creatTime': 'varchar(24) NOT NULL'
        })
        if DB.table('soup').count('id')==0:
            file = open('data/soup.txt','r',encoding='utf-8')
            ls = file.readlines()
            DB.table('soup').create({
                'id': 'INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT',
                'text': 'TEXT NOT NULL',
            }, insert=[{'text': item} for item in ls])
        DB.close()

短链生成API

@api.route('/', methods=['GET'])
def swURL():
    # url = request.values.get("url")
    host = f"{urlparse(request.host_url).scheme}s://{urlparse(request.host_url).netloc}/"
    url = urllib.parse.unquote(request.url.split("url=")[-1])
    if url == request.url:
        return jsonify({"code": 400, "msg": "请输入URL"})
    pattern = r'^(http|https|ftp|file)?:/{2}\w.+$'
    result = re.match(pattern, url)
    if result:
        DB_FILE_PATH = r'data/shorturl.db'
        shortDB = SqlHelper.Connect(DB_FILE_PATH)
        longURL = result[0]
        urlQuery = shortDB.table('shortURL').where(f"longUrl = '{longURL}'").find()
        if len(urlQuery) > 0:
            data = {'shortID': urlQuery[0]["shortID"], 'longUrl':  urlQuery[0]["longUrl"],"shortUrl": f'{host}{urlQuery[0]["shortID"]}','creatTime':  urlQuery[0]["creatTime"]}
            return jsonify({"code": 200, "msg": "URL已存在","data": data })
        shortID = s64(int(time.time()))
        data = {'shortID': shortID, 'longUrl': longURL,"shortUrl":f'{host}{shortID}','creatTime': time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())}
        shortDB.table("shortURL").add(data)
        shortDB.close()
        return jsonify({
            "code": 200, 
            "msg": "短链接创建成功!", 
            "data": data
        })
    return jsonify({"code": 400, "msg": "URL格式错误"})

这个API接口提取前端提交的长链接作为参数,然后为之生成一个专属短链ID,一并插入数据表,表结构如下所示:

关于短链ID的生成,我采用了将当前时间戳转化为64进制的方案:

table = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZαβ"
def s64(n: int):
    s = bin(n)[2:]
    if j := (h := len(s)) % 6:
        s = "0" * j + s
    return "".join([table[int(s[i : i + 6][::-1], 2)] for i in range(0, h, 6)])

长链接重定向

@route.route('/<shortID>', methods=['GET'])
def redirectUrl(shortID):
    DB_FILE_PATH = r'data/shorturl.db'
    shortDB = SqlHelper.Connect(DB_FILE_PATH)
    urlQuery = shortDB.table('shortURL').where(f"shortID = '{shortID}'").find()
    shortDB.close()
    if len(urlQuery) > 0:
        return redirect(urlQuery[0]['longUrl'])
    return redirect(url_for('route.index'))

短网址API

  1. 方法: GET, POST
  2. 接口: http(s)://[域名]/api
参数必选类型说明
urlstring需要转换的长链接

请求返回的数据结构:

{
    "code": 200,
    "data": {
        "creatTime": "2022-09-12 15:02:26",
        "longUrl": "https://www.ztyang.com",
        "shortID": "6zTC11",
        "shortUrl": "http://127.0.0.1:5000/6zTC11"
    },
    "msg": "短链接创建成功!"
}

心灵毒汤API

  1. 方法: GET,
  2. 接口: http(s)://[域名]/soup
  3. 参数: 无

请求成功返回的数据结构:

{
    "code": 200,
    "data": {
        "id": 432,
        "text": "遇到闪电记得要微笑,因为那是天空在给你拍照。"
    }
}

安装

这里以宝塔为例:

  1. 首先在宝塔软件商店里安装 python项目管理器v

  1. 将源码上传到宝塔任一指定的网站目录,如下图所示:

  1. 打开python项目管理器,填写相关安装信息:

注意:端口号需要提前打开,不然部署后会无法访问网站
  1. 域名映射,将域名解析到项目所部署的服务器,填写域名:

  1. 部署完成