短网址顾名思义就是使用比较短的网址代替很长的网址。维基百科上面的解释是这样的:
短网址又称网址缩短、缩短网址、URL 缩短等,指的是一种互联网上的技术与服务,此服务可以提供一个非常短小的 URL 以代替原来的可能较长的URL,将长的 URL 位址缩短。用户访问缩短后的 URL 时通常将会重定向到原来的长 URL
起源
虽然现在互联网已经非常发达了,但还是有很多场景会对用户输入的内容有长度限制。比如 :
微薄、Twitter 长度不能超过 140 个字
一些早期的 BBS 文章单行的长度不能超过 78 字符等场景
运营商短信的长度不能超过 70 个字
而现在很多媒体、电商平台的内容大多都是多人协作通过比较复杂的系统、框架生成的,链接长度几十个甚至上百字符都是很平常的事情,所以如果在上述的几个场景中传播链接使用短网址服务就是一个必然的结果。比如下面这些短信截图你应该不会陌生:
应用场景
短网址服务的最初本意就是缩短长 url,方便传播。但其实短网址服务还能做很多其他的事情。比如下面这些:
访问次数的限制,比如只能访问 1 次,第二次访问的时候就拒绝服务
时间的限制,比如只能在一周内提供访问服务,超过一周就拒绝服务
根据访问者的地域的限制
通过密码访问
访问量统计
高峰访问时间统计等等
统计访问者的一些信息,比如:
来源城市
访问时间
使用的终端设备、浏览器
访问来源 IP
在营销活动中其实还可以对不同的渠道生成不通的短网址,这样通过统计这些短网址还能判断不同渠道的访问量等信息
基于 Knative Serverless 技术实现一个短网址服务
在 Knative 模式下可以实现按需分配,没有流量的时候实例缩容到零,当有流量进来的时候再自动扩容实例提供服务。
现在我们就基于阿里云容器服务的 Knative 来实现一个 serverless 模式的短网址服务。本示例会给出一个完整的 demo,你可以自己在阿里云容器服务上面创建一个 Knative 集群,使用本示例提供服务。本示例中实现一个最简单的功能
通过接口实现长网址到短网址的映射服务
当用户通过浏览器访问短网址的时候通过 301 跳转到长网址
下面我们一步一步实现这个功能
数据库
既然要实现短网址到长网址的映射,那么就需要保存长网址的信息到数据库,并且生成一个短的 ID 作为短网址的一部分。所以我们首先需要选型使用什么数据库。在本示例中我们选择使用阿里云的表格存储,表格存储最大的优势就是按量服务,你只需要为你使用的量付费,而且价格也很实惠。如下所示的按量计费价格表。1G 的数据保存一年的费用是3.65292元/年( 0.000417 24 365=3.65292) ,是不是很划算。
短网址生成 API
我们需要有一个 API 生成短网址
/new?origin-url=${长网址}
origin-url 访问地址
返回结果
vEzm6v
假设我们服务的域名是 short-url.default.serverless.kuberun.com ,那么现在访问 http://short-url.default.serverless.kuberun.com/vEzm6v 就可以跳转到长网址了。
代码实现
package main
import (
"crypto/md5"
"encoding/hex"
"fmt"
"log"
"net/http"
"os"
"strconv"
"time"
"strings"
"github.com/aliyun/aliyun-tablestore-go-sdk/tablestore"
)
var (
alphabet = []byte("abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
l = &Log{}
)
func ShortUrl(url string) string {
md5Str := getMd5Str(url)
var tempVal int64
var result [4]string
for i := 0; i < 4; i++ {
tempSubStr := md5Str[i*8 : (i+1)*8]
hexVal, _ := strconv.ParseInt(tempSubStr, 16, 64)
tempVal = 0x3FFFFFFF & hexVal
var index int64
tempUri := []byte{}
for i := 0; i < 6; i++ {
index = 0x0000003D & tempVal
tempUri = append(tempUri, alphabet[index])
tempVal = tempVal >> 5
}
result[i] = string(tempUri)
}
return result[0]
}
func getMd5Str(str string) string {
m := md5.New()
m.Write([]byte(str))
c := m.Sum(nil)
return hex.EncodeToString(c)
}
type Log struct {
}
func (log *Log) Infof(format string, a ...interface{}) {
log.log("INFO", format, a...)
}
func (log *Log) Info(msg string) {
log.log("INFO", "%s", msg)
}
func (log *Log) Errorf(format string, a ...interface{}) {
log.log("ERROR", format, a...)
}
func (log *Log) Error(msg string) {
log.log("ERROR", "%s", msg)
}
func (log *Log) Fatalf(format string, a ...interface{}) {
log.log("FATAL", format, a...)
}
func (log *Log) Fatal(msg string) {
log.log("FATAL", "%s", msg)
}
func (log *Log) log(level, format string, a ...interface{}) {
var cstSh, _ = time.LoadLocation("Asia/Shanghai")
ft := fmt.Sprintf("%s %s %s\n", time.Now().In(cstSh).Format("2006-01-02 15:04:05"), level, format)
fmt.Printf(ft, a...)
}
func handler(w http.ResponseWriter, r *http.Request) {
l := &Log{}
l.Infof("Hello world received a request, url: %s", r.URL.Path)
l.Infof("url:%s ", r.URL)
//if r.URL.Path == "/favicon.ico" {
// http.NotFound(w, r)
// return
//}
urls := strings.Split(r.URL.Path, "/")
originUrl := getOriginUrl(urls[len(urls)-1])
http.Redirect(w, r, originUrl, http.StatusMovedPermanently)
}
func new(w http.ResponseWriter, r *http.Request) {
l.Infof("Hello world received a request, url: %s", r.URL)
l.Infof("url:%s ", r.URL)
originUrl, ok := r.URL.Query()["origin-url"]
if !ok {
l.Errorf("no origin-url params found")
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("Bad request!"))
return
}
surl := ShortUrl(originUrl[0])
save(surl, originUrl[0])
fmt.Fprint(w, surl)
}
func getOriginUrl(surl string) string {
endpoint := os.Getenv("OTS_TEST_ENDPOINT")
tableName := os.Getenv("TABLE_NAME")
instanceName := os.Getenv("OTS_TEST_INSTANCENAME")
accessKeyId := os.Getenv("OTS_TEST_KEYID")
accessKeySecret := os.Getenv("OTS_TEST_SECRET")
client := tablestore.NewClient(endpoint, instanceName, accessKeyId, accessKeySecret)
getRowRequest := &tablestore.GetRowRequest{}
criteria := &tablestore.SingleRowQueryCriteria{}
putPk := &tablestore.PrimaryKey{}
putPk.AddPrimaryKeyColumn("id", surl)
criteria.PrimaryKey = putPk
getRowRequest.SingleRowQueryCriteria = criteria
getRowRequest.SingleRowQueryCriteria.TableName = tableName
getRowRequest.SingleRowQueryCriteria.MaxVersion = 1
getResp, _ := client.GetRow(getRowRequest)
colmap := getResp.GetColumnMap()
return fmt.Sprintf("%s", colmap.Columns["originUrl"][0].Value)
}
func save(surl, originUrl string) {
endpoint := os.Getenv("OTS_TEST_ENDPOINT")
tableName := os.Getenv("TABLE_NAME")
instanceName := os.Getenv("OTS_TEST_INSTANCENAME")
accessKeyId := os.Getenv("OTS_TEST_KEYID")
accessKeySecret := os.Getenv("OTS_TEST_SECRET")
client := tablestore.NewClient(endpoint, instanceName, accessKeyId, accessKeySecret)
putRowRequest := &tablestore.PutRowRequest{}
putRowChange := &tablestore.PutRowChange{}
putRowChange.TableName = tableName
putPk := &tablestore.PrimaryKey{}
putPk.AddPrimaryKeyColumn("id", surl)
putRowChange.PrimaryKey = putPk
putRowChange.AddColumn("originUrl", originUrl)
putRowChange.SetCondition(tablestore.RowExistenceExpectation_IGNORE)
putRowRequest.PutRowChange = putRowChange
if _, err := client.PutRow(putRowRequest); err != nil {
l.Errorf("putrow failed with error: %s", err)
}
}
func main() {
http.HandleFunc("/", handler)
http.HandleFunc("/new", new)
port := os.Getenv("PORT")
if port == "" {
port = "9090"
}
if err := http.ListenAndServe(fmt.Sprintf(":%s", port), nil); err != nil {
log.Fatalf("ListenAndServe error:%s ", err.Error())
}
}
代码我已经编译成镜像,你可以直接使用 registry.cn-hangzhou.aliyuncs.com/knative-sample/shorturl:v1 此镜像编部署服务。
三步走起!!!
第一步 准备数据库
首先到阿里云开通表格存储服务,然后创建一个实例和表。我们需要的结构比较简单,只需要短 URL ID 到长 URL 的映射即可,存储表结构设计如下:
名称描述id短网址 IDoriginUrl长网址
第二步 获取 access key
登陆到阿里云以后鼠标浮动在页面的右上角头像,然后点击 accesskeys 跳转到 accesskeys 管理页面
点击显示即可显示 Access Key Secret
第三步 部署服务
Knative Service 的配置如下, 使用前两步的配置信息填充 Knative Service 的环境变量。然后部署到 Knative集群即可
apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: short-url
namespace: default
spec:
template:
metadata:
labels:
app: short-url
annotations:
autoscaling.knative.dev/maxScale: "20"
autoscaling.knative.dev/minScale: "0"
autoscaling.knative.dev/target: "100"
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/knative-sample/shorturl:v1
ports:
- name: http1
containerPort: 8080
env:
- name: OTS_TEST_ENDPOINT
value: http://t.cn-hangzhou.ots.aliyuncs.com
- name: TABLE_NAME
value: ${TABLE_NAME}
- name: OTS_TEST_INSTANCENAME
value: ${OTS_TEST_INSTANCENAME}
- name: OTS_TEST_KEYID
value: ${OTS_TEST_KEYID}
- name: OTS_TEST_SECRET
value: ${OTS_TEST_SECRET}
使用上面的 knative service 部署服务,部署好以后可能是下面这样:
└─# kubectl get ksvc
short-url http://short-url.default.serverless.kuberun.com short-url-456q9 short-url-456q9 True
现在可以开始测试
生成一个短网址
└─# curl 'http://short-url.default.serverless.kuberun.com/new?origin-url=https://help.aliyun.com/document_detail/121534.html?spm=a2c4g.11186623.6.786.41e074d9oHpbO2'
vEzm6v
curl 命令输出的结果 VR7baa 就是短网址的 ID
访问短网址
在浏览器中打开 http://short-url.default.serverless.kuberun.com/vEzm6v 就能跳转到长 url 网址了。
小结
本实战我们只需三步就基于 Knative 实现了一个 Serverless 的短网址服务,此短网址服务在没有请求的时候可以缩容到零节省计算资源,在有很多请求的时候可以自动扩容。并且使用了阿里云表格存储,这样数据库也是按需付费。基于 Knative + TableStore 实现了短网址服务的 Serverless 化。
本文作者:一绿舟
原文链接:https://yq.aliyun.com/articles/718936?utm_content=g_1000077682
本文为云栖社区原创内容,未经允许不得转载。
分享到:
相关推荐
内容概要:本文介绍了一款基于MATLAB GUI的学生成绩管理系统,旨在提升学校教学管理的效率和准确性。系统主要由三个模块组成:考试收录数据模块、考试数据分析模块和统计分析数据模块。它不仅支持成绩的录入、显示、排序、查找,还包括特征值分析、直方图绘制和教师评语录入等功能。通过对成绩数据的综合分析,系统能为学校教学管理提供客观科学的数据支持。 适合人群:教育工作者(如教师、管理人员)和技术爱好者(特别是对MATLAB GUI感兴趣的开发者)。 使用场景及目标:适用于各类学校和教育机构,用于管理和分析学生成绩,帮助教师和管理者更好地了解学生的学习状况,改进教学质量。 阅读建议:对于希望深入了解如何利用MATLAB GUI进行学生成绩管理的读者来说,本文提供了详细的系统设计思路和功能实现方法,值得仔细研读并尝试实践。
内容概要:本文介绍了基于T-Mats库的涡扇发动机气路故障仿真模型,涵盖了多种类型的故障植入(如部件流量、效率及压比故障),并允许自定义故障程序和组合。该模型通过对软阈值去噪处理后的信号序列进行分析,提取真实的运行扰动信息,确保输出数据符合CMAPASS的排列要求。此外,该模型能够模拟航空发动机的典型气路故障,帮助研发和技术人员更准确地预测和评估发动机性能,从而提前采取预防措施。 适合人群:航空航天领域的研发人员、技术人员以及对航空发动机故障仿真感兴趣的学者。 使用场景及目标:①用于研究和开发涡扇发动机的气路故障诊断系统;②辅助工程师进行故障预测和性能评估;③为后续数据分析和实验验证提供可靠的数据基础。 其他说明:该模型不仅提高了仿真的准确性,还增强了对发动机运行状态的理解,为提升发动机性能和可靠性提供了强有力的技术支持。
scratch少儿编程逻辑思维游戏源码-scratch冒险.zip
少儿编程scratch项目源代码文件案例素材-爬塔.zip
内容概要:本文详细探讨了合金凝固模型中的相场模拟方法及其在各向异性枝晶生长研究中的应用。首先介绍了合金凝固模型的基本概念及其在现代制造业中的重要性,特别是在激光增材制造、选择性激光熔融和定向凝固技术中的应用。接着,重点讨论了相场模拟作为一种数值模拟方法,在预测合金凝固过程中组织结构演变方面的关键作用。文中还提供了MATLAB实现合金各向异性枝晶生长的具体代码及详细注释,以及Comsol用于偏微分方程求解的雪花生长模型。最后,文章总结了当前的研究进展,并展望了未来的发展趋势。 适合人群:从事材料科学、冶金工程、激光增材制造领域的研究人员和技术人员,尤其是对相场模拟和合金凝固感兴趣的学者。 使用场景及目标:适用于希望深入了解合金凝固过程、相场模拟方法及其在现代制造技术中应用的专业人士。目标是提高对合金凝固机制的理解,优化制造工艺,提升产品质量。 其他说明:文章不仅提供了理论分析,还包括具体的代码实现和详细的文献参考资料,有助于读者全面掌握相关技术和最新研究进展。
少儿编程scratch项目源代码文件案例素材-史莱姆出击.zip
少儿编程scratch项目源代码文件案例素材-忍者酷跑.zip
scratch少儿编程逻辑思维游戏源码-点击灌篮.zip
内容概要:本文介绍了将基于RBF神经网络的PID控制器应用于永磁同步电机(PMSM)转速环控制的方法及其性能优势。传统的PID控制器在面对非线性和时变系统时存在参数整定困难的问题,而引入RBF神经网络可以实现实时在线调参,提高系统的灵活性和鲁棒性。文中详细描述了Simulink模型的设计,特别是Matlab s-function模块中RBF神经网络的具体实现,包括高斯函数激活和带惯性的权值更新机制。实验结果显示,在转速突变情况下,改进后的控制器能够迅速稳定系统,超调量控制在2%以内,调节时间较传统方法缩短约40%,并且在负载变化时表现出色,无需重新整定参数。 适合人群:从事电机控制系统研究和开发的技术人员,尤其是对PID控制器优化感兴趣的工程师。 使用场景及目标:适用于需要提升PMSM转速环控制精度和响应速度的应用场合,如工业自动化设备、机器人等领域。目标是通过引入智能算法解决传统PID控制器参数整定难题,提高系统性能。 阅读建议:关注RBF神经网络与PID控制器结合的具体实现细节,特别是在Matlab s-function模块中的编码技巧以及参数调整策略。同时,注意学习率的选择和动量项的作用,这对于实际应用至关重要。
scratch少儿编程逻辑思维游戏源码-Scratch 奔跑.zip
内容概要:本文详细介绍了基于COMSOL有限元软件的变压器辐射传热数值分析方法。首先,解释了变压器内外辐射传热的基本机理,包括热量通过传导、对流和辐射的方式传递,重点在于辐射传热的作用及其数学描述。接着,逐步引导读者从零开始构建有限元仿真模型,涵盖模型参数确定、网格划分、材料属性定义、边界条件设置、传热方程设定、仿真运行及结果分析等多个步骤。最后,探讨了进一步研究的方向,如不同因素(温度、材料属性、几何形状)对辐射传热的影响,以及该模型在电力电子设备和热管理系统的潜在应用。 适合人群:电气工程专业学生、初学者和技术爱好者,尤其是对有限元仿真和变压器辐射传热感兴趣的群体。 使用场景及目标:适用于希望通过实际操作掌握有限元仿真技能的人群,旨在帮助他们理解变压器辐射传热机制并能独立完成相关仿真项目。 其他说明:本文不仅提供了理论知识,还附带了详细的视频教程和仿真模型,使学习过程更加直观易懂。
内容概要:本文详细介绍了交错并联Boost PFC(功率因数校正)仿真电路模型的设计与实现,特别是在临界BCM模式下的双闭环控制特性。文章首先解释了该电路的经典结构及其优势,即能够有效降低开关损耗和电流纹波。接着,重点讨论了双闭环控制的具体实现方法,包括外环电压控制和内环电流控制的MATLAB/Simulink代码示例。文中还特别强调了电流环中零交叉检测的重要性以及交错并联结构中驱动信号相位差的精确设置。此外,作者分享了将模型从Simulink转换到Plecs和Psim时遇到的问题及解决方案,如更换为带反向恢复特性的二极管模型和重新校准控制环路的采样周期。最后,文章展示了优化后的电流波形图,验证了所提方法的有效性。 适合人群:电力电子工程师、电源设计师、从事电力系统仿真的研究人员和技术爱好者。 使用场景及目标:适用于需要进行高效电源设计的研究和开发项目,旨在提高电源系统的性能,减少谐波失真,提升功率因数校正效果。 其他说明:文中提供的具体代码片段和参数设置有助于读者更好地理解和复现实验结果。同时,对于希望深入理解双闭环控制系统和BCM模式的人来说,本文提供了宝贵的实践经验。
scratch少儿编程逻辑思维游戏源码-3000 横版闯过.zip
内容概要:本文介绍了如何利用Matlab/Simulink构建空气涡轮发动机的动态仿真模型。首先,文章详细阐述了各个部件级模型的设计,包括进气道、涡轮、气室、压气机、尾喷管、转子动力学模块和容积模块。接着,重点讨论了PID控制器在维持发动机转速恒定方面的作用,尤其是在面对输出扭矩阶跃扰动时的表现。最后,提供了简单的Simulink模型代码片段,展示了如何设置和运行仿真模型,以便实时监控和调整发动机性能。 适合人群:航空航天工程领域的研究人员和技术人员,尤其是那些对空气涡轮发动机仿真感兴趣的读者。 使用场景及目标:适用于希望通过Matlab/Simulink进行空气涡轮发动机仿真研究的专业人士。主要目标是掌握空气涡轮发动机各部件的工作原理及其相互关系,同时学会使用PID控制器优化发动机性能。 其他说明:本文不仅提供了理论知识,还附有实际操作步骤和代码示例,帮助读者更好地理解和应用所学内容。
少儿编程scratch项目源代码文件案例素材-收集能量.zip
scratch少儿编程逻辑思维游戏源码-弹回的球.zip
少儿编程scratch项目源代码文件案例素材-铅笔画.zip
Sage Decrypter.zip
scratch少儿编程逻辑思维游戏源码-躲避火箭.zip
KEPServerEX6-6.17.269.0,最新版