Upload file ขึ้น S3 โดยตรงด้วย Presigned URL [Golang]
ปัจจุบันถ้าพูดถึงเรื่องการจัดการ Storage ส่วนใหญ่ก็คงหนีไม่พ้นบริการเจ้าดังอย่าง Amazon S3 ที่มี API สำหรับใช้จัดการไฟล์หลากหลายภาษา ดังในบทความนี้ก็จะใช้ Golang เป็นหลัก
วิธีในการ Upload File ขึ้น server นั้น ในความเป็นจริงสามารถทำได้หลากหลายแบบ ขึ้นอยู่กับความต้องการของงาน จึงขอเปรียบเทียบตัวอย่างระหว่างการทำ Simple Upload กับ Presigned Upload เพื่อให้เห็นภาพได้ง่าย
Simple Upload
การ Upload แบบ 2 ชิ่ง ก็คือส่งไฟล์จาก Client >> Service >> S3
ข้อดีของการทำแบบดังกล่าวคือ Implement ง่าย แต่ไม่เหมาะกับระบบที่มี Load สูง ๆ เนื่องจากต้องมีการพัก Buffer ที่ Service นั่นเอง
Presigned Upload URL
การขอ URL เพื่อ Upload ไปที่ S3 โดยตรง ถ้าเทียบกับข้อข้างบนก็คือจาก
Client >> S3
ข้อดีคือทำให้ภาระการ Upload File ไปตกอยู่กับ AWS S3 โดยตรง ทำให้ Service มี Capacity สูง แต่แลกมาซึ่งความซับซ้อนในการ Implement
Step ในการทำ Presigned Upload URL มีดังนี้
- Service ขอ Presigned Upload URL จาก S3 API โดยขั้นตอนนี้สามารถกำหนด specs ข้อจำกัดต่าง ๆ ของไฟล์ได้ด้วย
- Service ส่ง Presigned Upload URL ให้ Client และเมื่อ User เริ่ม Upload File ก็จะใช้ request PUT method ไปยัง Presigned Upload URL ที่ได้มา
- หลังจากนั้นก็จะเป็นขั้นตอนของการ Update File Address ในฐานข้อมูลฝั่ง Service แล้ว ถึงตรงนี้แล้วแต่เราจะออกแบบเลยเพราะเราได้ Address มาตั้งแต่ Step ที่ 1 เรียบร้อยแล้ว
ตัวอย่าง
เราจะใช้ Fiber Framework + AWS SDK v2 ในการสาธิต โดยผู้เขียนจะมโนว่าผู้อ่านพอมีประสบการณ์ในการใช้ API Framework ที่ชื่อ Fiber มาบ้าง (ถ้ายังสามารถตามไปอ่าน URL ที่แปะไว้ก่อนได้)
- sdk package — github.com/aws/aws-sdk-go-v2 — pkg.go.dev
- gofiber/fiber: ⚡️ Express inspired web framework written in Go (github.com)
ผู้อ่านสามารถลองเอา Source Code ไปวางใน Folder ตาม package (บรรทัดที่ 1 ของแต่ละไฟล์) ได้เลย
หลังจากนั้นให้ใช้ Controller ไปต่อกับ Router แล้วลอง Request ไปที่ GetPresignedURL
ก็จะได้ URL สำหรับ Upload ประมาณนี้
https://presignedurldemo.s3.eu-west-2.amazonaws.com/just-example-file.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAJJWZ7B6WCRGMKFGQ%2F20180210%2Feu-west-2%2Fs3%2Faws4_request&X-Amz-Date=20180210T171315Z&X-Amz-Expires=1800&X-Amz-Signature=12b74b0788aa036bc7c3d03b3f20c61f1f91cc9ad8873e3314255dc479a25351&X-Amz-SignedHeaders=host
หลังจากนั้นใช้ Presigned URL ที่ได้มาไปใช้ทำ Request เพื่อส่ง Data Form แนบไฟล์รูปไป
ตัวอย่าง cURL
curl --location --request PUT 'https://presignedurldemo.s3.eu-west-2.amazonaws.com/just-example-file.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAJJWZ7B6WCRGMKFGQ%2F20180210%2Feu-west-2%2Fs3%2Faws4_request&X-Amz-Date=20180210T171315Z&X-Amz-Expires=1800&X-Amz-Signature=12b74b0788aa036bc7c3d03b3f20c61f1f91cc9ad8873e3314255dc479a25351&X-Amz-SignedHeaders=host' \--form 'file=@"/path/to/image.png"'
เสร็จแล้วเช็คใน S3 Bucket ก็จะพบไฟล์เราไปโผล่ตรงนั้นเรียบร้อย เป็นอันว่าสำเร็จ ซึ่งการ Upload ตรงนี้ก็จะมีเวลา Expired และ Option อื่น ๆ อีกมากมายที่สามารถศึกษาได้เพิ่มจาก AWS SDK Official Document