iT邦幫忙

2025 iThome 鐵人賽

DAY 5
0

說明

前面發行 Pre-Signed URL 需要透過 裝有 AWS CLI安置了 Key 的主機進行,這顯然會阻礙使用上的方便性。 我們接著來做一個 API Server 來接收請求,並且觸發指令,拿回 URL 後,回傳給使用者吧!

實作 API Server

原始碼

  • 下列原始碼,透過 Flask 框架撰寫,行為將分段解釋。
from flask import Flask, request, jsonify
import boto3
import os

app = Flask(__name__)

# AWS 設定(建議用 IAM Role 或環境變數,不要硬編 key)
AWS_ACCESS_KEY = os.getenv("AWS_ACCESS_KEY_ID")
AWS_SECRET_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")
AWS_REGION = "ap-northeast-1"
S3_BUCKET = "your-bucket-name"

s3_client = boto3.client(
    "s3",
    region_name=AWS_REGION,
    aws_access_key_id=AWS_ACCESS_KEY,
    aws_secret_access_key=AWS_SECRET_KEY
)

@app.route("/generate_presigned_url", methods=["POST"])
def generate_presigned_url():
    data = request.get_json()
    file_name = data.get("file_name")
    file_type = data.get("file_type", "application/octet-stream")

    if not file_name:
        return jsonify({"error": "file_name is required"}), 400

    try:
        presigned_url = s3_client.generate_presigned_url(
            "put_object",
            Params={
                "Bucket": S3_BUCKET,
                "Key": f"uploads/{file_name}",
                "ContentType": file_type
            },
            ExpiresIn=3600  # URL 有效期 (秒)
        )
        return jsonify({"url": presigned_url})
    except Exception as e:
        return jsonify({"error": str(e)}), 500

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=True)

機敏資訊 / Boto3 Client 登入

  • 從系統變數拿取 KEY 與 SECRET
  • 直接給定 REGION 就是東京,避免填錯區域 / 如果要抄到台北,那之後再改這邊。
  • Bucket 這邊改成我們先前定下來的 exsky-backup-media
AWS_ACCESS_KEY = os.getenv("AWS_ACCESS_KEY_ID")
AWS_SECRET_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")
AWS_REGION = "ap-northeast-1"
S3_BUCKET = "exsky-backup-media"

s3_client = boto3.client(
    "s3",
    region_name=AWS_REGION,
    aws_access_key_id=AWS_ACCESS_KEY,
    aws_secret_access_key=AWS_SECRET_KEY
)

Decorator + Function

  • 這一段,讓 generate_presigned_url 函式,可以透過 POST /generate_presigned_url路徑時,以 POST 請求輸入參數
  • 由 AWS SDK,Boto3 提供,s3_client.generate_presigned_url 去生成 URL
  • 最後將拿到的預簽網址,放到 json 格式中,回傳回去
@app.route("/generate_presigned_url", methods=["POST"])
def generate_presigned_url():
    data = request.get_json()
    file_name = data.get("file_name")
    file_type = data.get("file_type", "application/octet-stream")

    if not file_name:
        return jsonify({"error": "file_name is required"}), 400

    try:
        presigned_url = s3_client.generate_presigned_url(
            "put_object",
            Params={
                "Bucket": S3_BUCKET,
                "Key": f"uploads/{file_name}",
                "ContentType": file_type
            },
            ExpiresIn=3600  # URL 有效期 (秒)
        )
        return jsonify({"url": presigned_url})
    except Exception as e:
        return jsonify({"error": str(e)}), 500

主程式

  • 這邊會讓成是透過 python xxx.py 執行起來時,運作 app.run 這行,將伺服器開在指定的 port
if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8087, debug=True)

後記

  • 做好了程式,接著要決定程式放在哪裡跑? 機敏資料怎麼拿?
    1. 跑在 我的開發者 EC2 主機上,機敏資料放在系統變數...

      密鑰放在系統變數,可能會被幹走,有一點點風險

    2. 跑在 Amazon Lambda Function 上,機敏資訊存在 AWS Secrets Manager 服務中

      這個看起來不錯,但是 Amazon Lambda Function 最長只能連續執行 15 分鐘

    3. 透過 API Gateway 等待客戶上門,上門後再趕快召喚 Amazon Lambda Function 臨時工上班
    4. 還有很多種...

結論

  • 因為時間有限,開發要時間還要測試,所以我先選擇做法ㄧ,放在自己的 EC2 上喔!!
  • 下一篇繼續說明

上一篇
【Day 4】 使用 Elemental MediaConvert 轉檔
系列文
無法成為片師也想拍 Vlog?!個人影音小工具的誕生!5
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言