如何在 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])。


分享到:


相關文章: