「Serverless云开发72变」随时随地短链

> 阿里云云开发平台,让每一个创新变成可能 <

Servreless运行过程

「Serverless云开发72变」随时随地短链

开发背景

你有没有发现,我们的任务中出现长 URL 就会比较麻烦?在微博这些限制字数的应用里。好处不言而喻。短、字符少、美观、便于发布、传播。如果有一个短址生成器就好了。市面上越来越多产品下线,如某杜的dmz仅限于为企业用户提供服务;新浪则不对外提供他t.cn等。利用这个机会尝试一下简单的 Web 全栈开发。

思考

本人是就读云计算技术与与应用,学的东西主要偏向服务器相关运维,此次选择Serverless云开发Fass想看下与传统开发与运维有什么区别。

开发

云开发代码: codeup.aliyun 仓库
欢迎小伙伴提建议和共同改进

「Serverless云开发72变」随时随地短链

设计思路

当我们在浏览器里输入 https://url.catni.cn/ARJreq

  1. DNS首先解析获得 url.catni.cn 的 IP 地址
  2. DNS 获得 IP 地址以后(比如:127.0.0.1),会向这个地址发送 HTTP GET 请求,查询短码 ARJreq
  3. https://url.catni.cn/ 服务器会通过短码 ARJreq 获取对应的长 URL
  4. 请求通过 HTTP 302 转到对应的长 URL https://workbench.aliyun.com/

*这里有个小的知识点,为什么要用 302 跳转而不是 301 呐?

301 是永久重定向,302 是临时重定向。短地址一经生成就不会变化,所以用 301 是符合 http 语义的。同时对服务器压力也会有一定减少。
但是如果使用了 301,我们就无法统计到短地址被点击的次数了。而这个点击次数是一个非常有意思的大数据分析数据源。能够分析出的东西非常非常多。所以选择302虽然会增加服务器压力,但是我想是一个更好的选择。

主要函数设计

from django.http import HttpResponseRedirect
from django.shortcuts import render, redirect
from .models import urlList
from .common.utils import json_response
from .common.arithmetic import ShortUrlGenerator
import os

# Create your views here.
def index(request):
    return render(request, 'indexview/index.html')


def generate(request):
    '''
    短链生成
    :param request:
    :return: data
    '''
    sourceUrl = request.GET.get('sourceUrl')
    shortUrl = ShortUrlGenerator(sourceUrl)
    sourceUrlCheck = urlList.objects.filter(sourceUrl=sourceUrl)
    if sourceUrlCheck.count() == 0:
        safetyCheckFlag = safetyCheck(sourceUrl)
        if safetyCheckFlag == '未发现威胁':
            primaryKey = shortUrl.shortUrl()[1]
            urlList.objects.create(sourceUrl=sourceUrl, primaryKey=primaryKey)
            flag = True
        else:
            return json_response(code=-1, msg=f'该网址存在分析:{safetyCheckFlag},不给予申请短链')
    else:
        primaryKey = urlList.objects.get(sourceUrl=sourceUrl).primaryKey
        flag = False
    data = {
        'flag': flag,
        'sourceUrl': sourceUrl,
        'primaryKey': primaryKey
    }
    print(data)
    return json_response(code=0, msg='获取成功!', data=data)


def safetyCheck(url):
    '''
    链接安全性检测
    :param url
    :return 链接安全性
    '''
    import requests
    main = ['未发现威胁', '未发现威胁', '未发现威胁', '欺诈', '风险', '违法']
    url = 'http://api.anquan.baidu.com/bsb/lookup?url=' + url
    headers = {
        'apikey': os.environ['BD_apikey']
    }

    res = requests.get(url, headers=headers).json()['result'][0]['main']
    return main[res]


def open(request, primaryKey):
    '''
    302跳转
    '''
    sourceUrl = urlList.objects.get(primaryKey=primaryKey).sourceUrl
    return redirect(sourceUrl)

路由设计

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('generate', views.generate, name='generat'),
    path('<str:primaryKey>', views.open, name='open'),
]

服务依赖

前端使用原生的html进行开发(bootstrap,axios)
后端当然是选择入门友好的框架了Django

算法实现

实现原理:将长串(或者长串+冲突次数)用MD5生成32位摘要信息,每两位为定义字符数组长度做与操作得到定义字符数组的下标值,取对应的字符,生成16位的特殊字符,取其中的N位做为短串返回。

该算法来源于微博[原始的算法是C# 版本,我只是对其改写成python版本]

import hashlib


class ShortUrlGenerator:
    '''
    :param url
    :return 4组短链数组
    '''

    def __init__(self, url):
        self.url = url

    def shortUrl(self):
        key = "HiramUrl"
        chars = ["a", "b", "c", "d", "e", "f", "g", "h",
                 "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
                 "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",
                 "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H",
                 "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
                 "U", "V", "W", "X", "Y", "Z"
                 ]
        sMD5EncryptResult = hashlib.md5((key + self.url).encode("utf8"))
        hexString = sMD5EncryptResult.hexdigest()
        resUrl = []
        for i in range(4):
            # 把加密字符按照 8 位一组 16 进制与 0x3FFFFFFF 进行位与运算
            sTempSubString = hexString[i * 8: (i + 1) * 8]
            hex16 = '0x' + sTempSubString
            lHexLong = 0x3FFFFFFF & eval(hex16)
            outChars = ""
            for j in range(6):
                # 把得到的值与 0x0000003D 进行位与运算,取得字符数组 chars 索引
                index = 0x0000003D & lHexLong
                # 把取得的字符相加
                outChars += chars[index]
                # 每次循环按位右移 5 位
                lHexLong = lHexLong >> 5

            # 把字符串存入对应索引的输出数组
            resUrl.append(outChars)
        return resUrl


如有小伙伴有更好的想法来实现这部分,可以在下方留言

后期功能扩展

检测:鉴别用户是否输入了不合法的链接(目前已接入某度的网址安全检测),如有则上报网安等措施
接口:采用DRF(Django REST framework)规范相关接口
自定义:设置自定义后缀,访问密码等
统计:点击量、访问的 ip 地域、用户使用的设备
当拥有一定的数据基础后,可进行大数据开发分析,这将是一部巨大的财富

迁移应注意的地方

  1. Q: 由于打包上传环境需要将第三方包一起打包,在安装包时,都要装在项目根目录,目录会显示非常的混乱,建议本地开发完后上传至云平台部署。
    
    A: 目前暂时还没有有效的解决方案。最合理的是通过pythonpath设置三方包的路径,可是目前fc环境无法设置动态的环境变量,比如

    PYTHONPATH=${PWD}/modules

  2. 根据README和文档:Python Django 应用迁移方案

    文档中在上传你的 Django 应用时,是将默认startproject后进入该项目的文件进行上传,然而在项目开发中完全不会采用这种方法进行操作,解决方案是
    
    配置应用入口,打开 serverless_config.py 文件,更新 FRAMEWORK 配置
    
    FRAMEWORK = {
            'module': 'DJANGO_SETTINGS_MODULE文件,一般settings.py,不要加 .py 后缀'
    }
    
    重要:将module设置为 项目名.settings
  1. 不支持使用db.sqlite3,这就是serverless模式和paas区别,计算资源必须是无状态
  2. 然后我就是用阿里的RDS-mysql数据库进行数据迁移,需使用独立出口IP 注意:不要使用0.0.0.0/0,这并不安全
  3. django后台不能正常登陆到后台,原因未知

小结

  1. 在 serverless 里, 资源的所有权被压缩到一个函数的执行期间内, 资源利用率更高, 费用也就更便宜。 特别适用于小流量用户或流量分布很不均衡的用户。
  2. 采用b/s模式,打开浏览器就能0成本开发,一键部署应用。CloudIDE内置Node.js、Java、Python、PHP等常见环境,省去繁琐的配置工作,让您只需专注于业务逻辑的开发。同时提供免费的云上开发和测试环境以及测试域名,还支持多个小伙伴在线协同,随时随地无缝开发。
  3. 云开发平台提供的 Cloud-Native 集成研发环境支持本地研发和在线研发模式,支持云上测试环境,预发环境,正式环境三套环境的部署。可以更好的提供单元测试,冒烟测试等常规上限流程。????????????
  4. 至于免运维,虽然节省了不少环境的部署,但还有点距离(目前看来市场还是需要运维人员的,hhh), 相比在架构上的灵活性,平台可迁移性上的损失,可以忽略不计。
  5. serverless是趋势,但在项目框架这方面还是要下功夫。

还没有使用过Serverless云开发?

现在花3分钟体验新手任务即领10元阿里云无门槛代金券。
Serverless「Serverless云开发72变」随时随地短链

本文参加Serverless云开发的有奖征文活动,已经获得作者授权

上一篇:「Serverless云开发72变」来左边跟我一起画个龙,右边跟我用AntV画个图


下一篇:解决linux删除文件后空间没有释放问题