一个无聊的网站
2023年9月14日
本文是无聊网站的第一篇,主要介绍了无聊网站freeupdateme.com的建站起因、网站功能、网站架构、技术难点、代码模板和参考资料。
建站起因
很久之前,在网上看到过一篇文章,讲述了一个无意义的网站。这个网站只有一个按钮,一个倒计时和一行文字。如果用户在一定的时间内(也没有具体说明是多久)不点击这个按钮,该网站将永远关闭,据说到发文为止,网站也不曾关闭。可惜,我从未找到这个网站。但是某一天当我又想起这个事情的时候,突然意识到,我可以自己去验证这个事情。
网站功能
基本功能
网站的功能其实很简单,主要是为了统计用户操作网页这个动作之间的时间间隔。用户需要操作一个输入框,输入并确认。然后将用户输入的内容显示在页面上。当用户再次输入时,显示内容会被覆盖。后台数据库会保存用户输入内容,输入时间和IP地址。这样就可以拿到用户输入的内容和时间,进行分析。
趣味功能
为了更好玩,我增加了下面的一些功能,并附上了网站截图:
- 添加了一个计时器,显示最后一次输入到当前的时间
- 添加了IP地址信息,利用ip2region解析IP地址获得
- 添加了今日剩余更新次数,今日更新次数和总更新次数
- 添加了词云图,使用结巴中文分词,图片绘制使用wordcloud2在线生成。
网站架构
功能确定后,就需要确定网站架构。在这里我们使用AWS云,主要服务有Route53, API Gateway、Lambda、DynamoDB和S3,整体架构如下图。
网站响应流程:
- 浏览器发送请求到Route53,S3(用于加载页面的图片资源)
- Route53将请求路由到API Gateway
- API Gateway触发Lambda
- Lambda运行并处理逻辑
技术难点
在构建网站时遇到了一个问题,VPC内Lambda不能够访问Dynamodb。解决这个问题可以有三个思路
- 给Lambda访问公网能力,这样通过公网连接Dynamodb。
- 这个方案在执行后还是不能够连接Dynamodb,原因是Lambda作为serverless不能够有public ip,参考stackoverflow的回答
- 使用dynamoDB的VPC endpoint,Lambda不通过公网连接Dynamodb。
- 这个方案可行,但是需要创建额外资源,而且Lambda实际上是可以不部署在VPC内的。所以就有了第三个方案。
- 将Lambda部署在非VPC环境内,这样Lambda和Dynamodb在同一个环境,就可以访问了
- 这个方案架构简单,仅部署需要的资源,不需要配置VPC和Subnet,省事了不少。
代码模板
在这里仅展示可复用的代码,AWS资源创建cloudformation和部署脚本
资源模板
click here to show
resources.yml
file---
AWSTemplateFormatVersion: "2010-09-09"
Description: Free update me
Transform: "AWS::Serverless-2016-10-31"
Parameters:
AppName:
Type: String
Resources:
API:
Type: AWS::Serverless::Api
Properties:
StageName: api
TracingEnabled: true
OpenApiVersion: 3.0.2
LambdaFunction:
Type: "AWS::Serverless::Function"
Properties:
CodeUri: ../dist/
FunctionName: !Ref AppName
Environment:
Variables:
REGION: !Ref "AWS::Region"
Handler: freeUpdateMeHandler.handler
MemorySize: 128
Runtime: nodejs18.x
Timeout: 60
Policies:
- Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:GetItem
Resource: !GetAtt FreeUpdateMeDynamoDBTable.Arn
Tracing: Active
Events:
getEndpoint:
Type: Api
Properties:
RestApiId: !Ref API
Path: /
Method: GET
postEndpoint:
Type: Api
Properties:
RestApiId: !Ref API
Path: /
Method: POST
LogGroup:
Type: "AWS::Logs::LogGroup"
DependsOn: LambdaFunction
Properties:
LogGroupName: !Join
- /
- - /aws/lambda
- !Ref LambdaFunction
RetentionInDays: 1
FreeUpdateMeDynamoDBTable:
Type: "AWS::DynamoDB::Table"
Properties:
TableName: free-update-me
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
脚本
aws cloudformation package \
--region $AWS_REGION \
--template-file $ORIGINAL_TEMPLATE_PATH \
--output-template-file $COMPILED_TEMPLATE_PATH \
--s3-bucket $BUCKET \
--s3-prefix $APP_NAME \
--use-json
aws cloudformation deploy \
--region $AWS_REGION \
--stack-name $APP_NAME \
--template-file $COMPILED_TEMPLATE_PATH \
--parameter-overrides file://$PARAMETER_FILE_PATH \
--tags $TAGS \
--capabilities CAPABILITY_IAM