沒有 web 接口開發經驗,只會簡單寫一寫功能函數,有沒有辦法寫一個收集客戶端數據的接口呢?本文將一步步帶你如何在沒有接口開發經驗的狀況下輕鬆的使用 AWS 服務器服務構建本身定製化的 API 接口。html
假設 T 公司有一個全球性的網站,每一個國家站點都有一個下載頁面。公司想要去監測全球用戶的下載狀況,須要對下載按鈕進行埋點,那咱們就須要有一個接口能夠監測到用戶的下載狀況,須要記錄的數據有以下:python
咱們不可能針對每一個站點都作一個連接做爲藉口,最好的方式就是建立一個連接,經過傳遞不一樣的參數來埋到不一樣的下載按鈕,連接相似下面結構:linux
https://down.wzlinux.com?type=CN https://down.wzlinux.com?type=US https://down.wzlinux.com?type=IN
看到這個需求,一個專業的開發人員可能很快能夠解決,須要較高的開發技能,還須要運維購買服務器,部署等,相對來講比較麻煩,而且管理起來相對複雜。本文所展現的就是你只會簡單的功能函數開發便可完成這個需求的開發部署,並且所有使用 AWS 的無服務器組件,用戶不須要再關係底層硬件,來多少請求量咱們就花多少錢,也能夠節省沒必要要的支出。web
咱們知道在 web 裏面重要的一個組合 LAMP(Linux + Apache + MySQL + PHP)。在 AWS 中呢,也有一個無服務器架構組合 Lambda + API Gateway + DynamoDB,這個組合正好知足咱們的需求。API Gateway 用來接收用戶的請求數據,是實現 web api 的重要組件,Lambda 用來實現邏輯處理,選擇用戶須要的數據,DynamoDB 用來存儲 Lambda 的數據。數據庫
整個架構有一些依賴關係,Lambda 依賴 DynamoDB,API Gateway 依賴 Lambda,因此咱們先去建立 DynamoDB 表,而後去建立 Lambda 函數,最後建立 API Gateway。json
全部的操做均選擇在 AWS us-east-1 區域。api
建立 DynamoDB 很是簡單,在 Console 簡單點幾下就能夠,由於 DynamoDB 須要一個主鍵,咱們把生成的 uuid 做爲主鍵,填寫完成建立便可。安全
是否是很簡單,就這樣建立好了,若是你使用 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。服務器
由於 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": "*" } ] }
建立 Lambda 也比較簡單,大部分參數選擇默認便可,注意在 Permissions 裏面選擇咱們上面建立好的 Role,運行環境咱們選擇 Python,固然 Lambda 也支持 .NET、Go、Java、Node.js、Ruby,甚至還支持用戶自定義運行環境。
我這裏已經把 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。
pip
的 --target
選項在新的項目本地 package
目錄中安裝庫。~/my-function$ pip install --target ./package requests
~/my-function$ cd package ~/my-function/package$ zip -r9 ${OLDPWD}/wzlinux-down.zip .
~/my-function/package$ cd $OLDPWD ~/my-function$ zip -g wzlinux-down.zip lambda_function.py
打包好的代碼包wzlinux-down.zip
能夠直接傳到 Lambda,也能夠先傳到 S3,再上傳到 Lambda,上傳完成以後以下:
注意:由於咱們代碼中有環境變量,就是咱們前面建立的 DynamoDB,在環境變量這一列建立好便可。
DB_TABLE_NAME:wzlinux-down
點擊右上角的測試,咱們發送測試的 json,這裏咱們就模擬 HTTP API,直接把上面的示例數據帖進去便可。
選擇執行,查看到已經執行成功了。
而後再去查看 DynamoDB 中,是否已經有數據寫入。
至此,咱們的 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 中
建立好以後,咱們直接請求這個連接訪問看看效果,固然咱們能夠再連接後面傳遞參數 type,如請求地址:
https://jat553o58l.execute-api.us-east-1.amazonaws.com/?type=CN https://jat553o58l.execute-api.us-east-1.amazonaws.com/?type=US
一樣查看一下 DynamoDB 數據庫,查看數據是否入庫:
爲了方便記錄,咱們可使用本身的域名,在 Custom domain names 裏面進行建立。
建立好以後,咱們爲域名添加 CNAME 解析,解析值爲 API Gateway domain name。
解析完成以後,咱們須要爲自定義域名配置一個 API mapping。
而後咱們就可使用咱們最開始規劃的地址進行訪問了。
https://down.wzlinux.com?type=CN https://down.wzlinux.com?type=US https://down.wzlinux.com?type=IN
咱們經過一個 URL,傳遞不一樣的參數,爲各個國家生成了不一樣的接口,只須要埋到對應的頁面,當用戶訪問的時候,咱們就會捕獲到數據,進而能夠進行分析。
AWS 這一套服務器架構(API Gateway + Lambda + DynamoDB),極大的減輕了咱們開發 API 接口的工做量,使得只是簡單懂得處理邏輯的函數開發人員便可完成 API 的開發,而且無服務器架構還有不少傳統應用不具備的優點,能夠預見無服務器架構會成爲雲計算的下一個紀元:
在第一次配置調試過程當中,註定會遇到各式各樣的問題,你們必定要充分利用 CloudWatch Logs 這個服務,咱們的不少報錯均可以在裏面找到,最後,若是你們都已經學會了,那就開啓你的無服務之旅吧,充分利用雲原生的一些功能,把咱們的應用進行現代化。