没有 web 接口开发经验,只会简单写一写功能函数,有没有办法写一个收集客户端数据的接口呢?本文将一步步带你如何在没有接口开发经验的情况下轻松的使用 AWS 服务器服务构建自己定制化的 API 接口。
一、前期准备
1.1、业务需求
假设 T 公司有一个全球性的网站,每个国家站点都有一个下载页面。公司想要去监测全球用户的下载情况,需要对下载按钮进行埋点,那我们就需要有一个接口可以监测到用户的下载情况,D Q ? c S p - k需要记录的数据有如下:
- countr b w U ]ry:用户来自哪个国家
- create_time:下载时间
- ip:用户的 IP
- referer:从哪个页面下载的
- site:国家站点代码
我们不可Q o u , * G w能针对每个站点都做一个链接作为借口,最好的方式就是创建一个链接,通过传递不同的参数来埋到不同的下载按钮,链接类似下面结构:
https://down.wzlinux.com?type=CN
https://down.wzlinux.comn R A . X ) ?type=US
https://down.wzlinux.com?type=IN
1.2、解决方案
看到这个需求,一个专业的开发人员可能很快可以解决,需要较高的开发技能,还需要运维购买服务` ; N器,部署等,相对来说比较麻烦,并且管理起来相对复杂。本文所展示的就是你_ o & | j h t H只会简单的功能函数开发即可完成这个需求的开发部署,而且全部使用 AWS 的无服务器组件,用户不需要再关系底层硬件,来多少请求量我们就花多少钱,也可以节省不必要的支出。
我们知道在 web 里面重要的一个组合 LAMP(Linux + Apache + My0 | 2SQL + PHP)。在i 8 | = 4 AWS 中呢,也有一个P A N @ ( N U h ~无服务器架构2 G U组合 LT 1 6 t K * ] Y 9ambda + APt 7 f ? H 9 q p KI Gateway + Dyns r lamoDB,这个组合正好满足我们的需求。API Gateway 用来接收用户的请求数据,是实现 web api 的重要组件,Lambda 用来实现逻辑处理,选择用户需要的数据,DynamoDB 用来存储 Lambda 的数据。
二、部署
整个架构有一些依赖关系,Lambda 依赖 DynamoDu D ^ 8 + P CB,API Gateway 依赖 Lambda,U y - ] F V {所以我q n j + b D m们先去创建 DynamoDB 表,然后去创建 Lam + } | 4mbda 函数,最后创建 API Gateway。
所有的操作均选择在 AWS us-east-1 区域。
2.| x 0 t 9 R &1、创建 DynamoDB
创建 Dynamf + ^ doDB 非常n h h z : B T简单,在 Console 简单点几下就可以,因为 DynamoDB 需要一个主键,我们把生成的 uuid 作/ ~ z t } ~ N 7为主键,填写! 6 T K 完成创建即可。
是不是很简单,就这样创建好了,如果你使用 aL x F 9 w w 5 6wscli 创建的话,那更简单:
aws dynamodb creT % ^ Q 6 8ate-table \
--table-name wzlinux-down \
--attribute-definitions AttributeName=id,AttributeType=S \
--key-schema AttributeName=id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST \
--region us-east-1
就这样简Z ~ M y 4 e b %单的创建好了,下面我们开始创建3 | ; S W ? P L比较重要的 Lambda= U Y d ^ 5 9。
2.2、创建 Lambda
创建角色权限
因为 Lambda 需要有权限向 DynamoDB 写入数据,我们可以自己创建一个 Lambda 角色,赋予对呀的权限,在创建的时候,把我们所创建的 Role 赋予 Lambda,我这里给的资源范围大了一些,安全要求高的,可以给予最小的权限,权限 json 如下:
{
"Version": "2012 Q M A P 0 u d2-10-17",
"Statement": [
{
"$ v kEffect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents",
"loZ 2 ] 8 E (gs:CreQ } EateLogGroup",
"dynamodb:PutItem",
"dyny ? ! O x G k g uamodb:Scan",
"dynamodb:Query",
"dynamodb:UpdateItem"
],
"Resource": "*"
}
]
}
console 创建
创建 Lambda 也比较简单,大部分参数选择默认即可,注意在 Permissions 里面选择我们上面创建好的 Role,运行环境我们选择 Python,当然 Lambda 也支持 .NET、Go、Java、Node.js、Ruby,甚至还支持用户自定义运I b Q G Y w s =行环境。
制作代码包
我这里已经把 Lambda 函数写好了,文件命名为lambda_fO % . } T P G L *unction.py
。
import boto3
import os
import uR : f l f 7 ( Yuid
import time
from requests import get
def lambda_handleru f S U Y ^ Y X A(event, context):
recordId = str(uuid.uuid4())
ctime = time.N U Z rstrftime("%Y-%m-%d %H:%M:%S", time.localtime())
sourceIT { ^ mP = event["headers"]["x-forwarded-for"]
url = "https://ax * R 7pi.ipdata.co/{0}/country_name?api-key=40b58339be0ec3ba64fb936da37dbab9c9d1677f335c50910c52aeb7".format(sourceIP)
country = gv 9 @ n t m { $et(url).text
try:
referer = event["headers"][( 5 H 5 m % G L C"referer"]
except:
referer = "NULL"
try:
site = eg [ J ` n + y % vvent["queryStringParameters"]["type"]
except:
site = "NULL"
# Createing ne^ v _ (w record in DynamoDB^ 8 z d S T x Q M table
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table(os5 f 0 v E.environ['DB_TABLE_NAME'])
table.put_item(
I{ z M 9 item={
'id': recordId,
'site': site,
'create_time': cl 8 E = i w i d Qtime,
'ip': sourceIP,
'country': country,
'referer' : refA O n , [ z ] berer
}
)
return {"statusCode": 200, "body": "OI $ N C HK"}
大致介绍一下函数,我们从 API Gateway 传入的参数获取用户来源 IP,然后通过一个接口把 IP 转换为国家。
再一个就是获取链接从哪个页面请求过来的,还有一个就是给我上面传入的参数 type 的取值。
Lambda 获取的参数主要通过 eveF U P j / Rnt 传递进来,event 是 API Gateway 传过来的参数,我们使用最简单的 HTTP API,我这边记录了传过来的 evt q | Q Oent,详细信息可以参照官方文档,这样大家就可以更加理解 Lambda 函数是怎么截取M q k的数据。
{
"version": "2.0",
"routeKey": "GET /",
"rawPath": "/",
"rawQueryString": "type=CN",
"headers": {
"accept": "text/html,application/xhtml+j R D ! k ^ c 9xml,application/xmq z Nl;q=0.9,image/webp,image/apng,*/*;q=0.8,applica$ 6 G S = s e ition/signed-exchangp ! ^ 6 , 9 y b [e;v=b3;q=0.9",
"accept-encodin8 U 8g": "gzip, deflate,Y # c z ( m br",
"accept-language": "zh-CN,zh;q=u d M 7 @0.9",
"content-length": "0",
"hX + j W * s w 1ost": "49imv2pyz1.execute-api.us-east-1.amazonaws.ck ; om",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "none",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0 (WindowT m e s 9 L ; Xs NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.41471 ] i 4 ? j [.105 S; ~ 2 % } - F ~ fafari/537.36",
"x-amzn-trace-id* a A 7 n H 6": "Root=1-5f2f6066-93614D 1 O 1 Y x Z Lfb0bb62a21428cb8508",
"x-forwarded-for": "52.221.86.56",
"x-forwarI ~ B y Wded-port": "443",
"x-forwarded-proto": "https"
},
"queryStringParameters": {
"type": "CN"
},
"requestContext": {
"accountId": "921283538843",
"apiId": "49imv2pyz1"R ( Q V [,
"domainName": "49imv2pyz1.exe| Q ` j scute-api.u# n S H J e u qs-east-1.aG U # c ^ ) G 1 Ymazonaws.com",
"domainPrefixn O 5 e O e h": "49i@ ` # t & bmv2pyz- * H # 61",
"http": {
"mM } m ! gethod": "GET",
"path": "/",
"protocol": "HTTP/1.1",
"sourceIp": "52.221.86.56",
"userAgent": "Mozilla/5.0 (Windows NT o r 4 * C 1 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 SaQ - m | ~fari/537.36"
},
"reI _ dquestId": "Q-wAChzJoAMq M d * K T y 5ESlQ=",
+ W ` p + m M L ~"routeKey": "GET /",
"stage": "$default",
"time": "09/Aug9 T N ` F n/2020:02:$ ) C u33:10 +0000",
"timeEpoch": 1596940390575
},
"isBase64EncodeV ] Q d": "False"
}
因为 python y k M E u # z 函数有依赖包,我们需要把依赖包一并打包传到 Lambda,关于打包的过程如下,我们这里用到的依赖包为 requI V i q - 5 - B qests。
- 使用
pip
的--target
选项在新的项目本地package
目录中安装库。
~/my-functS W O ] 1ion$ pip install --target ./package requests
- 创建包含依赖项的 ZIP 存档。
~/my-function$ cd packP W N k % *age
~/my-functq 5 4 2 O X J wion/package$ zip -r9 ${OLDPWD}/wzlinux-down.zip .
- 将您的函数代码添加到存档中。
~/my-function/package$ cd $OLDPWD
~/my-function$ zip -g wzlinux-down.zip lambda_function.py
上传代码包
打包好的代码包wzl+ 5 ( P ] = y Dint p } 7 ) Fux-down.zip
可以直接传到 Lambda,也可以先F . G C + u p w y传到 S3,再上传到 Lambda,上传完成之后如下:
注意:因为我们代码中有环境变量,就是我们r ; 6 t T , # p |前面v + +创建的 DynamoDB,在环境变量这一列创建好即可。
DBD E 5 % w V R s_TABLE_NAME:wzlinux-down
模拟测试
点击右上角的测试,我们发送测试; H P K ^ w 4的 json,这里我们就模拟 HTTP API,直接把上面的示例数据帖进去即可。
选择执行,查看x ^ [ h g O 8到已经执行成功Z 8 _ B I @了。
然后再去查看 DynamoDB 中,是否已经有数据写入, % { f 3 { ; 9。
至此,我们的 Lambda 已经打通,同样附上使用 awscli 创建 Lambda 的命令,需要我们提前把代码和依赖库打包上传到 S3。
aws lambda create-function \
--function-name wzlinux-down \
--runtime python3.8 \
--role arG 5 sn:aws:iam::921q A - w 3 S283538843:role^ p , y T 8 s { #/wzlinux-down-role \
--hau T . - @ H 7 Lndler lambda_function.lambda_handler \
--code S3Bucket^ w I=code.wzlinux.com,S3Key=wzlinux-down.zip \
--environment Variables={DB_TABLE_NAME=wzlinux-x E B : Hdown} \
--region us-east-1
--role:选择你创建好的 Role
--code:这里是我打包好的代码,上传M e u d B P到了我的 S3 中
2.3、创建 HTTP API
Console 创建
- 第一步,选择要集成的g U J 5 Lambda 函数,已经 API 名称。
- 第二步,设置路由,我们这里就选择默认的根目录吧,方法选择 GET。
- 第三步,阶段方面也就选择默认吧,毕竟我们不会经常去发布新版本的 API。
访问测U l + h ] 试
创建好之后,我们直接请求这个链接访问看看效果,当然我们可以再链接后面传递参数 type,如请求地址:# 4 i P ( V U 2
https://jat553o5R E L8l.execute-api.us-east-1.amazonaws.com/?type=CN
https://jat553o58l.R @ l % *execute-api.us-east-1.amazonaws.com/?type=US
同样查看一下 DynamoDB 数据库,查看数据是否入库:
自定义域名
为了方便记录,我们可以使用自己的域名,在 Custom domain names 里面进行创建。
创建好之后,我们为域名添加 CNAME 解析,解析值为 API Gateway domain name。
解析完成之后,我们需要为自定义域名配置一个 API mapping。
然后我们就可以使用我们最开始规划的地址进行访问了。
https://down.wzliN j u y k ( o `nux.com?type=CN
htJ B x = , ftps://down.wzlina T Xux.com?type=US
https://down.wzlinux.com?type=IN
我们通过一个 URL,传递不同的参数,为各个国家生成了不同的接口,只需要埋到对应的页面,当用户访问的时候,我们就会捕获到数据,进而可以进行! T 8 y * G 9 s分析。
三、总结
AWS 这一套服务器架构(API Gateway + Lambda + Dynamo8 R eDB),极大的减轻了我们开发 API 接口的工作量,使得只是简单懂得处理逻辑的函数开发人员即可完成 API 的开发,并且无服务器架构还有很多传统应用不具有的优势,5 | ~ ! S S R可以预见无服务器架构会成为云计算的下一个纪元:
- 便宜:只有使用的时候才需要付费
- 可扩展:根据负载动态扩展
- 降低运维:不需要维护底层硬件和系统
- 用户体验:允许公司投入更多时间和资源来开发和改进面向客户的功能。
在第一次配置调试过程中,注定会遇到各式各样的问题,大家一定要充分利用 CloudWatch Logs 这个服务,我们的很多报错都可以在里面找到,最后,如果大家都已经学会了,那就开启你的无服务之旅吧,充分利用云原生的一些功能,把我们的应用进行现代化。
发表评论