> 阿里云云开发平台,让每一个创新变成可能 <
Servreless运行过程
开发背景
你有没有发现,我们的任务中出现长 URL 就会比较麻烦?在微博这些限制字数的应用里。好处不言而喻。短、字符少、美观、便于发布、传播。如果有一个短址生成器就好了。市面上越来越多产品下线,如某杜的dmz仅限于为企业用户提供服务;新浪则不对外提供他t.cn等。利用这个机会尝试一下简单的 Web 全栈开发。
思考
本人是就读云计算技术与与应用,学的东西主要偏向服务器相关运维,此次选择Serverless云开发Fass想看下与传统开发与运维有什么区别。
开发
云开发代码: codeup.aliyun 仓库
欢迎小伙伴提建议和共同改进
设计思路
当我们在浏览器里输入 https://url.catni.cn/ARJreq 时
- DNS首先解析获得 url.catni.cn 的
IP
地址 - 当
DNS
获得IP
地址以后(比如:127.0.0.1),会向这个地址发送HTTP
GET
请求,查询短码ARJreq
-
https://url.catni.cn/ 服务器会通过短码
ARJreq
获取对应的长 URL - 请求通过
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 地域、用户使用的设备
当拥有一定的数据基础后,可进行大数据开发分析,这将是一部巨大的财富
迁移应注意的地方
-
Q: 由于打包上传环境需要将第三方包一起打包,在安装包时,都要装在项目根目录,目录会显示非常的混乱,建议本地开发完后上传至云平台部署。 A: 目前暂时还没有有效的解决方案。最合理的是通过pythonpath设置三方包的路径,可是目前fc环境无法设置动态的环境变量,比如
PYTHONPATH=${PWD}/modules
-
根据README和文档:Python Django 应用迁移方案
文档中在上传你的 Django 应用时,是将默认startproject后进入该项目的文件进行上传,然而在项目开发中完全不会采用这种方法进行操作,解决方案是
配置应用入口,打开 serverless_config.py 文件,更新 FRAMEWORK 配置 FRAMEWORK = { 'module': 'DJANGO_SETTINGS_MODULE文件,一般settings.py,不要加 .py 后缀' } 重要:将module设置为 项目名.settings
- 不支持使用db.sqlite3,这就是serverless模式和paas区别,计算资源必须是无状态
- 然后我就是用阿里的RDS-mysql数据库进行数据迁移,需使用独立出口IP 注意:不要使用0.0.0.0/0,这并不安全
- django后台不能正常登陆到后台,原因未知
小结
- 在 serverless 里, 资源的所有权被压缩到一个函数的执行期间内, 资源利用率更高, 费用也就更便宜。 特别适用于小流量用户或流量分布很不均衡的用户。
- 采用b/s模式,打开浏览器就能0成本开发,一键部署应用。CloudIDE内置Node.js、Java、Python、PHP等常见环境,省去繁琐的配置工作,让您只需专注于业务逻辑的开发。同时提供免费的云上开发和测试环境以及测试域名,还支持多个小伙伴在线协同,随时随地无缝开发。
- 云开发平台提供的 Cloud-Native 集成研发环境支持本地研发和在线研发模式,支持云上测试环境,预发环境,正式环境三套环境的部署。可以更好的提供单元测试,冒烟测试等常规上限流程。????????????
- 至于免运维,虽然节省了不少环境的部署,但还有点距离(目前看来市场还是需要运维人员的,hhh), 相比在架构上的灵活性,平台可迁移性上的损失,可以忽略不计。
- serverless是趋势,但在项目框架这方面还是要下功夫。
还没有使用过Serverless云开发?
现在花3分钟体验新手任务即领10元阿里云无门槛代金券。
Serverless
本文参加Serverless云开发的有奖征文活动,已经获得作者授权