您好,登录后才能下订单哦!
# Serverless 中怎么创建一个短网址服务
## 引言
在当今互联网时代,短网址服务已成为分享长链接的必备工具。传统短网址服务需要维护服务器和基础设施,而Serverless架构的出现彻底改变了这一模式。本文将详细介绍如何利用Serverless技术栈(AWS Lambda + API Gateway + DynamoDB)构建一个高可用、低成本的短网址服务。
## 一、Serverless架构概述
### 1.1 什么是Serverless
Serverless是一种云计算执行模型,其核心特点是:
- **无需管理服务器**:云服务商自动分配计算资源
- **事件驱动**:通过特定事件触发代码执行
- **按使用付费**:只对实际消耗的资源计费
- **自动弹性伸缩**:根据负载自动调整资源
### 1.2 为什么选择Serverless构建短网址服务
传统架构痛点:
- 需要预置服务器资源
- 流量突增时需手动扩容
- 存在资源闲置浪费
Serverless优势:
- 零基础设施管理
- 毫秒级自动扩容
- 成本效益显著(百万次调用约需$0.20)
## 二、技术选型与架构设计
### 2.1 核心组件
| 服务 | 作用 |
|---------------|-----------------------------|
| AWS Lambda | 处理URL转换的业务逻辑 |
| API Gateway | 提供RESTful接口 |
| DynamoDB | 存储原始URL与短码的映射关系 |
| Route53 | 域名解析(可选) |
### 2.2 数据流示意图
用户请求 -> API Gateway -> Lambda -> DynamoDB ↑ ↓ 响应生成 <- 错误处理
### 2.3 短码生成算法比较
| 算法 | 优点 | 缺点 |
|----------------|----------------------|----------------------|
| 自增ID+Base62 | 无冲突、有序 | 需维护计数器 |
| 哈希截断 | 分布式友好 | 可能冲突需重试 |
| UUID | 唯一性保证 | 长度较长(8字符以上) |
推荐实现(Python示例):
```python
import hashlib
import base64
def generate_short_code(url, length=6):
md5 = hashlib.md5(url.encode()).digest()
b64 = base64.urlsafe_b64encode(md5).decode()
return b64[:length].replace('_', 'x').replace('-', 'y')
aws configure
npm install -g serverless
serverless create --template aws-python3 --path url-shortener
cd url-shortener
目录结构:
.
├── handler.py # Lambda函数代码
├── serverless.yml # 资源配置文件
└── requirements.txt # Python依赖
serverless.yml
资源配置片段:
resources:
Resources:
ShortUrlsTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: short-urls
AttributeDefinitions:
- AttributeName: shortCode
AttributeType: S
KeySchema:
- AttributeName: shortCode
KeyType: HASH
BillingMode: PAY_PER_REQUEST
TimeToLiveSpecification:
AttributeName: expiryTime
Enabled: true
handler.py
核心代码:
import os
import boto3
from datetime import datetime, timedelta
from urllib.parse import urlparse
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(os.environ['TABLE_NAME'])
def create_short_url(event, context):
body = json.loads(event['body'])
original_url = body['url']
if not urlparse(original_url).scheme:
original_url = 'https://' + original_url
short_code = generate_short_code(original_url)
table.put_item(
Item={
'shortCode': short_code,
'originalUrl': original_url,
'createdAt': datetime.utcnow().isoformat(),
'expiryTime': int((datetime.now() + timedelta(days=365)).timestamp(),
'clickCount': 0
}
)
return {
'statusCode': 200,
'body': json.dumps({
'shortUrl': f"https://{event['headers']['Host']}/{short_code}"
})
}
def redirect_short_url(event, context):
short_code = event['pathParameters']['code']
response = table.update_item(
Key={'shortCode': short_code},
UpdateExpression='ADD clickCount :incr',
ExpressionAttributeValues={':incr': 1},
ReturnValues='UPDATED_NEW'
)
return {
'statusCode': 301,
'headers': {'Location': response['Item']['originalUrl']}
}
serverless.yml
中的事件定义:
functions:
create:
handler: handler.create_short_url
events:
- http:
path: /url
method: post
cors: true
redirect:
handler: handler.redirect_short_url
events:
- http:
path: /{code}
method: get
部署命令:
serverless deploy
测试创建短链:
curl -X POST https://xxx.execute-api.region.amazonaws.com/dev/url \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/very/long/url"}'
访问短链:
curl -v https://xxx.execute-api.region.amazonaws.com/dev/abc123
增强DynamoDB项:
{
'shortCode': 'abc123',
'originalUrl': 'https://example.com',
'analytics': {
'lastAccessed': '2023-07-20T08:00:00Z',
'referrers': {
'direct': 42,
'twitter': 15
},
'deviceTypes': {
'mobile': 30,
'desktop': 27
}
}
}
利用DynamoDB TTL特性:
1. 设置expiryTime
属性
2. 配置Lambda处理过期项:
resources:
Resources:
CleanupRule:
Type: AWS::Events::Rule
Properties:
ScheduleExpression: 'rate(1 day)'
Targets:
- Arn: !GetAtt CleanupFunction.Arn
添加Redis缓存层(AWS ElastiCache):
import redis
cache = redis.Redis(host=os.environ['REDIS_HOST'])
def redirect_short_url(event, context):
short_code = event['pathParameters']['code']
# 先查缓存
original_url = cache.get(f"url:{short_code}")
if original_url:
return {'statusCode': 301, 'headers': {'Location': original_url}}
# 缓存未命中则查数据库
response = table.get_item(Key={'shortCode': short_code})
...
防滥用:
内容过滤: “`python BLACKLIST_DOMNS = [‘malware.com’, ‘phishing.site’]
def validate_url(url): domain = urlparse(url).netloc return not any(bad in domain for bad in BLACKLIST_DOMNS)
## 六、成本估算
假设每月100万次请求:
| 服务 | 单价 | 月成本 |
|----------------|-------------------|---------|
| Lambda | $0.20/百万请求 | $0.20 |
| API Gateway | $1.00/百万请求 | $1.00 |
| DynamoDB | $0.25/百万读写单位 | $0.50 |
| **总计** | | **$1.70** |
## 七、替代方案比较
### 7.1 其他云服务商实现
| 平台 | 等效服务组合 | 特点 |
|------------|--------------------------|-------------------------|
| Azure | Functions + CosmosDB | 与Microsoft生态集成度高 |
| GCP | Cloud Functions + Firestore | 实时数据库能力突出 |
### 7.2 开源框架方案
使用Serverless Framework插件:
```yaml
plugins:
- serverless-dynamodb-local
- serverless-offline
本地开发命令:
serverless dynamodb install
serverless offline start
通过本文的实践,我们完成了: 1. 完全Serverless的短网址服务搭建 2. 实现了核心的创建/跳转功能 3. 添加了访问统计等高级特性 4. 确保了系统的安全性和经济性
Serverless架构使得个人开发者也能轻松构建高可用的生产级服务。读者可以在此基础上继续扩展: - 添加用户系统 - 实现可视化数据看板 - 开发浏览器插件等客户端
资源推荐: - AWS Serverless 官方文档 - Serverless Framework 示例库 - 短链接算法研究论文 “`
(注:实际字符数约3100字,此处显示为缩略版本,完整实现需包含更多错误处理和边界情况处理代码)
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。