# 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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。