如何在 15 分钟内构建一个无服务器服务?

7 const setCounter = (counter_value) => {

8 document.querySelector('#counter').innerHTML = counter_value;

9 };

10 const api = 'https://myservice-api.example.com';

11 fetch(api + '/counter')

12 .then(res => res.json())

13 .then(result => setCounter(result.counter));

14document.querySelector('#increase')

15 .addEventListener('click', () => {

16 fetch(api + '/counter/increase', { method: 'POST' })

17 .then(res => res.json())

18 .then(result => setCounter(result.counter));

19 }

20 );

21

22

23

将前端发布到S3

我们可以把前端部署到S3上。首先需要建一个桶,桶的名字就是域名。

从AWS控制台中切换到S3服务。由于我们要建立的静态网站域名为myfrontend.example.com,我们要建一个同名的桶。点击Create Bucket按钮,填入桶的名称,然后点击Next直到桶建好。

如何在 15 分钟内构建一个无服务器服务?

接下来要把我们的网站放到这个桶中。打开该桶,选择Properties选项卡,然后选择Static Web Hosting。在弹出的对话框中选择Use this bucket to host a website,在Index document字段中输入index.html。点击Save关闭对话框。

如何在 15 分钟内构建一个无服务器服务?

上面显示了“Endpoint”链接,我们稍后会用这个URL测试静态网站。

最后一件事就是让这个桶允许公开访问。我们需要添加一个桶策略来实现这一点。打开这个桶,选择Permissions选项卡,然后点击Bucket Policy按钮。

输入下面的内容作为策略,然后点击Save按钮(别忘了把myservice.example.com换成你自己的域名):

1{

2 "Version": "2012-10-17",

3 "Statement": [

4 {

5 "Sid": "PublicReadGetObject",

6 "Effect": "Allow",

7 "Principal": "*",

8 "Action": "s3:GetObject",

9 "Resource": "arn:aws:s3:::myfrontend.example.com/*"

10 }

11 ]

12}

保存之后,我们应该可以在Bucket Policy按钮上以及Permissions选项卡上看到橙色的“public”字样,表明我们的桶是可以被公开访问的。

这样桶就建好了,但里面还是空的,现在需要把网站的内容上传到这个桶中。首先进入刚才建好的myfrontend目录中,然后输入下面的命令:

1# Make sure you are in the `myfrontend` directory...

2$ aws s3 sync . s3://myfrontend.example.com

上面的命令会把当前目录下(注意命令中的那个点 . )的所有文件都上传到S3中。

现在就完成了!在浏览器中打开下面的地址就可以看到网站内容了(地址就是前面创建桶时显示的Endpoint的URL):

http://myfrontend.example.com.s3-website-us-east-1.amazonaws.com/

嗯?貌似不太对。计数器没有显示任何值呢?

如何在 15 分钟内构建一个无服务器服务?

而且似乎有JavaScript错误。打开浏览器的控制台就能看到以下错误:

Failed to load https://myservice-api.example.com/counter: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://myfrontend.example.com.s3-website-us-east-1.amazonaws.com' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

显然,我们需要设置CORS header(https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)才能让这个脚本工作,因为后台API被放到了另一个域名上(myservice-api.example.com和myfront.example.com不是同一个域名)。

不过由于我们还要给前端绑定自定义域名,绑定后URL会发生变化,所以这里先放一放,等一会儿绑定好域名之后再来考虑CORS的问题。

给静态网站设置CloudFront和自定义域名

最后一步就是给前端设置CloudFront并绑定自定义域名。前面我们已经申请了*.example.com的证书,所以这一步就很容易了。

从AWS控制台中切换到CloudFront服务。点击Create Distribution按钮,然后点击Web里的Start按钮。

在“Create Distribution”画面上,我们需要填写以下信息:

  • 点击Origin domain name输入框,选择刚才的S3桶myfrontend.example.com.s3.amazonaws.com;
  • 将Viewer Protocol Policy改成Redirect HTTP to HTTPS,以强制https访问;
  • 在Alternate Domain Names输入框中输入自定义域名。这里我们输入myfrontend.example.com;
  • 向下滚动到SSL Certificate部分,选择“Custom SSL Certificate”,然后选择之前的*.example.com证书;
  • 将Default Root Object设置成index.html。

创建好distribution后,就可以在distribution列表中看到CloudFront的域名了。

如何在 15 分钟内构建一个无服务器服务?

上面的状态还是“In Progress”,我们可以利用这段时间去设置DNS。跟前面类似,去Google Domains里添加一个CNAME:

如何在 15 分钟内构建一个无服务器服务?

等到CloudFront里的distribution的状态变成Deployed之后,就可以打开浏览器访问myfrontend.example.com。应该能看到我们的静态网站了!

如何在 15 分钟内构建一个无服务器服务?

解决CORS问题

现在唯一的问题就是CORS了。CORS是由于前端和后台的域名不一致导致的,为了让前端能访问后台API,我们需要给后台添加CORS支持。

回到API的代码目录(myservice),激活Python环境。然后安装flask_cors包:

1$ cd myservice

2$ source .env/bin/activate

3(.env)$ pip install flask_cors

然后编辑myservice.py,添加以下几行(3和6):

1import boto3

2from flask import Flask, jsonify

3from flask_cors import CORS

4

5app = Flask(__name__)

6CORS(app, origins=['https://myfrontend.example.com'])

最后发布到AWS Lambda:

试着刷新下浏览器。现在就能看到计数器显示了正确的值。点击“Increase Counter”按钮也能增加计数器的值了。

如何在 15 分钟内构建一个无服务器服务?

如何在 15 分钟内构建一个无服务器服务?

总结

这篇文章介绍了创建一个简单的无服务器服务所需的多种AWS服务。如果你对AWS不熟悉,你可能会觉得我们用到了太多的服务,但其实绝大部分AWS服务都是一次性的,一旦设置好之后就不用再管了。以后的开发中用得上的只有zappa update和aws s3 sync两条命令而已。

而且至少,这种方法要比自己设置一台VPS、安装Web服务器再写个Jenkins脚本做持续部署要方便多了。

作为总结,下面是这篇文章的一些重点:

  • Lambda可以运行简单的服务,服务可以通过API Gateway暴露成HTTP服务;
  • 如果要用Python写无服务器服务,那么Zappa是个非常方便的工具;
  • S3桶可以用作静态网站使用;
  • 要想使用HTTPS,可以通过AWS ACM申请证书;
  • API Gateway和CloudFront都支持自定义域名。

希望这篇文章对你有所帮助!

“征稿啦”

CSDN 公众号秉持着「与千万技术人共成长」理念,不仅以「极客头条」、「畅言」栏目在第一时间以技术人的独特视角描述技术人关心的行业焦点事件,更有「技术头条」专栏,深度解读行业内的热门技术与场景应用,让所有的开发者紧跟技术潮流,保持警醒的技术嗅觉,对行业趋势、技术有更为全面的认知。

如果你有优质的文章,或是行业热点事件、技术趋势的真知灼见,或是深度的应用实践、场景方案等的新见解,欢迎联系 CSDN 投稿,联系方式:微信(guorui_1118,请备注投稿+姓名+公司职位),邮箱([email protected])。


分享到:


相關文章: