【AWS徵文】帶你使用 AWS 無服務器架構一步步打造個性化 API 接口

沒有 web 接口開發經驗,只會簡單寫一寫功能函數,有沒有辦法寫一個收集客戶端數據的接口呢?本文將一步步帶你如何在沒有接口開發經驗的狀況下輕鬆的使用 AWS 服務器服務構建本身定製化的 API 接口。html

1、前期準備

1.一、業務需求

假設 T 公司有一個全球性的網站,每一個國家站點都有一個下載頁面。公司想要去監測全球用戶的下載狀況,須要對下載按鈕進行埋點,那咱們就須要有一個接口能夠監測到用戶的下載狀況,須要記錄的數據有以下:python

  • country:用戶來自哪一個國家
  • create_time:下載時間
  • ip:用戶的 IP
  • referer:從哪一個頁面下載的
  • site:國家站點代碼

咱們不可能針對每一個站點都作一個連接做爲藉口,最好的方式就是建立一個連接,經過傳遞不一樣的參數來埋到不一樣的下載按鈕,連接相似下面結構:linux

https://down.wzlinux.com?type=CN
https://down.wzlinux.com?type=US
https://down.wzlinux.com?type=IN

1.二、解決方案

看到這個需求,一個專業的開發人員可能很快能夠解決,須要較高的開發技能,還須要運維購買服務器,部署等,相對來講比較麻煩,而且管理起來相對複雜。本文所展現的就是你只會簡單的功能函數開發便可完成這個需求的開發部署,並且所有使用 AWS 的無服務器組件,用戶不須要再關係底層硬件,來多少請求量咱們就花多少錢,也能夠節省沒必要要的支出。web

咱們知道在 web 裏面重要的一個組合 LAMP(Linux + Apache + MySQL + PHP)。在 AWS 中呢,也有一個無服務器架構組合 Lambda + API Gateway + DynamoDB,這個組合正好知足咱們的需求。API Gateway 用來接收用戶的請求數據,是實現 web api 的重要組件,Lambda 用來實現邏輯處理,選擇用戶須要的數據,DynamoDB 用來存儲 Lambda 的數據。數據庫

image-20200807174608309

2、部署

整個架構有一些依賴關係,Lambda 依賴 DynamoDB,API Gateway 依賴 Lambda,因此咱們先去建立 DynamoDB 表,而後去建立 Lambda 函數,最後建立 API Gateway。json

全部的操做均選擇在 AWS us-east-1 區域。api

2.一、建立 DynamoDB

建立 DynamoDB 很是簡單,在 Console 簡單點幾下就能夠,由於 DynamoDB 須要一個主鍵,咱們把生成的 uuid 做爲主鍵,填寫完成建立便可。安全

image-20200807175509048

是否是很簡單,就這樣建立好了,若是你使用 awscli 建立的話,那更簡單:bash

aws dynamodb create-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

就這樣簡單的建立好了,下面咱們開始建立比較重要的 Lambda。服務器

2.二、建立 Lambda

建立角色權限

由於 Lambda 須要有權限向 DynamoDB 寫入數據,咱們能夠本身建立一個 Lambda 角色,賦予對呀的權限,在建立的時候,把咱們所建立的 Role 賦予 Lambda,我這裏給的資源範圍大了一些,安全要求高的,能夠給予最小的權限,權限 json 以下:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents",
                "logs:CreateLogGroup",
                "dynamodb:PutItem",
                "dynamodb:Scan",
                "dynamodb:Query",
                "dynamodb:UpdateItem"
            ],
            "Resource": "*"
        }
    ]
}

console 建立

建立 Lambda 也比較簡單,大部分參數選擇默認便可,注意在 Permissions 裏面選擇咱們上面建立好的 Role,運行環境咱們選擇 Python,固然 Lambda 也支持 .NET、Go、Java、Node.js、Ruby,甚至還支持用戶自定義運行環境。

image-20200807181426650

製做代碼包

我這裏已經把 Lambda 函數寫好了,文件命名爲lambda_function.py

import boto3
import os
import uuid
import time
from requests import get

def lambda_handler(event, context):
    recordId = str(uuid.uuid4())
    ctime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())

    sourceIP = event["headers"]["x-forwarded-for"]
    url = "https://api.ipdata.co/{0}/country_name?api-key=40b58339be0ec3ba64fb936da37dbab9c9d1677f335c50910c52aeb7".format(sourceIP)
    country = get(url).text
    try:
        referer = event["headers"]["referer"]
    except:
        referer = "NULL"

    try:
        site = event["queryStringParameters"]["type"]
    except:
        site = "NULL"

    # Createing new record in DynamoDB table
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table(os.environ['DB_TABLE_NAME'])
    table.put_item(
        Item={
            'id': recordId,
            'site': site,
            'create_time': ctime,
            'ip': sourceIP,
            'country': country,
            'referer' : referer
        }
    )
    return {"statusCode": 200, "body": "OK"}

大體介紹一下函數,咱們從 API Gateway 傳入的參數獲取用戶來源 IP,而後經過一個接口把 IP 轉換爲國家。

再一個就是獲取連接從哪一個頁面請求過來的,還有一個就是給我上面傳入的參數 type 的取值。

Lambda 獲取的參數主要經過 event 傳遞進來,event 是 API Gateway 傳過來的參數,咱們使用最簡單的 HTTP API,我這邊記錄了傳過來的 event,詳細信息能夠參照官方文檔,這樣你們就能夠更加理解 Lambda 函數是怎麼截取的數據。

{
    "version": "2.0",
    "routeKey": "GET /",
    "rawPath": "/",
    "rawQueryString": "type=CN",
    "headers": {
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
        "accept-encoding": "gzip, deflate, br",
        "accept-language": "zh-CN,zh;q=0.9",
        "content-length": "0",
        "host": "49imv2pyz1.execute-api.us-east-1.amazonaws.com",
        "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 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36",
        "x-amzn-trace-id": "Root=1-5f2f6066-93614fb0bb62a21428cb8508",
        "x-forwarded-for": "52.221.86.56",
        "x-forwarded-port": "443",
        "x-forwarded-proto": "https"
    },
    "queryStringParameters": {
        "type": "CN"
    },
    "requestContext": {
        "accountId": "921283538843",
        "apiId": "49imv2pyz1",
        "domainName": "49imv2pyz1.execute-api.us-east-1.amazonaws.com",
        "domainPrefix": "49imv2pyz1",
        "http": {
            "method": "GET",
            "path": "/",
            "protocol": "HTTP/1.1",
            "sourceIp": "52.221.86.56",
            "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36"
        },
        "requestId": "Q-wAChzJoAMESlQ=",
        "routeKey": "GET /",
        "stage": "$default",
        "time": "09/Aug/2020:02:33:10 +0000",
        "timeEpoch": 1596940390575
    },
    "isBase64Encoded": "False"
}

由於 python 函數有依賴包,咱們須要把依賴包一併打包傳到 Lambda,關於打包的過程以下,咱們這裏用到的依賴包爲 requests。

  1. 使用 pip--target 選項在新的項目本地 package 目錄中安裝庫。
~/my-function$ pip install --target ./package requests
  1. 建立包含依賴項的 ZIP 存檔。
~/my-function$ cd package
~/my-function/package$ zip -r9 ${OLDPWD}/wzlinux-down.zip .
  1. 將您的函數代碼添加到存檔中。
~/my-function/package$ cd $OLDPWD
~/my-function$ zip -g wzlinux-down.zip lambda_function.py

上傳代碼包

打包好的代碼包wzlinux-down.zip能夠直接傳到 Lambda,也能夠先傳到 S3,再上傳到 Lambda,上傳完成以後以下:

image-20200809111714931

注意:由於咱們代碼中有環境變量,就是咱們前面建立的 DynamoDB,在環境變量這一列建立好便可。

DB_TABLE_NAME:wzlinux-down

模擬測試

點擊右上角的測試,咱們發送測試的 json,這裏咱們就模擬 HTTP API,直接把上面的示例數據帖進去便可。

image-20200809112338953

選擇執行,查看到已經執行成功了。

image-20200809112434981

而後再去查看 DynamoDB 中,是否已經有數據寫入。

image-20200809112646453

至此,咱們的 Lambda 已經打通,一樣附上使用 awscli 建立 Lambda 的命令,須要咱們提早把代碼和依賴庫打包上傳到 S3。

aws lambda create-function \
    --function-name wzlinux-down \
    --runtime python3.8 \
    --role arn:aws:iam::921283538843:role/wzlinux-down-role \
    --handler lambda_function.lambda_handler \
    --code S3Bucket=code.wzlinux.com,S3Key=wzlinux-down.zip \
    --environment Variables={DB_TABLE_NAME=wzlinux-down} \
    --region us-east-1

--role:選擇你建立好的 Role

--code:這裏是我打包好的代碼,上傳到了個人 S3 中

2.三、建立 HTTP API

Console 建立

  1. 第一步,選擇要集成的 Lambda 函數,已經 API 名稱。

image-20200809113204675

  1. 第二步,設置路由,咱們這裏就選擇默認的根目錄吧,方法選擇 GET。

image-20200809113325886

  1. 第三步,階段方面也就選擇默認吧,畢竟咱們不會常常去發佈新版本的 API。

image-20200809113518605

訪問測試

建立好以後,咱們直接請求這個連接訪問看看效果,固然咱們能夠再連接後面傳遞參數 type,如請求地址:

https://jat553o58l.execute-api.us-east-1.amazonaws.com/?type=CN
https://jat553o58l.execute-api.us-east-1.amazonaws.com/?type=US

image-20200809113724110

一樣查看一下 DynamoDB 數據庫,查看數據是否入庫:

image-20200809114018289

自定義域名

爲了方便記錄,咱們可使用本身的域名,在 Custom domain names 裏面進行建立。

image-20200809115454420

建立好以後,咱們爲域名添加 CNAME 解析,解析值爲 API Gateway domain name。

image-20200809115848616

解析完成以後,咱們須要爲自定義域名配置一個 API mapping。

image-20200809210604715

image-20200809210639796

而後咱們就可使用咱們最開始規劃的地址進行訪問了。

https://down.wzlinux.com?type=CN
https://down.wzlinux.com?type=US
https://down.wzlinux.com?type=IN

咱們經過一個 URL,傳遞不一樣的參數,爲各個國家生成了不一樣的接口,只須要埋到對應的頁面,當用戶訪問的時候,咱們就會捕獲到數據,進而能夠進行分析。

3、總結

AWS 這一套服務器架構(API Gateway + Lambda + DynamoDB),極大的減輕了咱們開發 API 接口的工做量,使得只是簡單懂得處理邏輯的函數開發人員便可完成 API 的開發,而且無服務器架構還有不少傳統應用不具備的優點,能夠預見無服務器架構會成爲雲計算的下一個紀元:

  • 便宜:只有使用的時候才須要付費
  • 可擴展:根據負載動態擴展
  • 下降運維:不須要維護底層硬件和系統
  • 用戶體驗:容許公司投入更多時間和資源來開發和改進面向客戶的功能。

在第一次配置調試過程當中,註定會遇到各式各樣的問題,你們必定要充分利用 CloudWatch Logs 這個服務,咱們的不少報錯均可以在裏面找到,最後,若是你們都已經學會了,那就開啓你的無服務之旅吧,充分利用雲原生的一些功能,把咱們的應用進行現代化。

歡迎你們掃碼關注,獲取更多信息

【AWS徵文】帶你使用 AWS 無服務器架構一步步打造個性化 API 接口

相關文章
相關標籤/搜索