Introdution
- Bài này mình sẽ viết về cách upload files lên S3 của Amazon.
- S3 là dịch vụ lưu trữ file của AWS. Trước khi sử dụng dịch vụ ta cần tạo Bucket( nơi sẽ chứa các file chúng ta upload lên).
- FYI: Khi tạo tài khoản AWS một số dịch vụ sẽ free trong 12 tháng: EC2, S3, RDS, CloudFront ( nhớ đọc kỹ free như thế nào ví S3 sẽ free 5GB, 20k GET request và 2k PUT request – chỉ thế thôi, hơn tính phí đấy nên cẩn thận). Tuy nhiên nhiên một số dịch vụ khác lại luôn luôn miễn phí ( kể cả sau 12 tháng – nên tha hồ nghịch): DynamoDB, Lamda..
Before start
- Trước khi bắt đầu ta cần có 1 tài khoản AWS ( nếu bạn chưa có thì tạo nha).
- Tạo mới (nếu bạn chưa có) một AWS Access Key.
Create Bucket
- Sau khi có tài khoản và Access Key chúng ta cần tạo Bucket để test upload file.
- Có nhiều cách để có thể tạo Bucket:
- Khi tạo Bucket còn rất nhiều thiết lập (tạo thử đi sẽ thấy
) như region, public, CORS.. theo mình cách 1 và 2 (tạo trên trang AWS, aws cli) chỉ nên thực hiện test cho biết. Còn lại nên tạo bằng API như vậy các thông số thiết lập sẽ được lưu lại không cần phải nhớ.
- Trước khi bắt đầu chúng ta set up project một chút.
- Tạo folder, khởi tạp project, khởi tạo git với các lệnh12345mkdir nodejs-aws-s3cd nodejs-aws-s3npm init -ygit init
- Tạo file
config.json
với nội dung:1234567<span class="token punctuation">{</span><span class="token property">"BUCKET"</span><span class="token operator">:</span> <span class="token string">"created-by-api"</span><span class="token punctuation">,</span><span class="token property">"REGION"</span><span class="token operator">:</span> <span class="token string">"ap-southeast-1"</span><span class="token punctuation">,</span><span class="token property">"AWS_ACCESS_KEY"</span><span class="token operator">:</span> <span class="token string">"NHAP_ACCESS_KEY_CUA_BAN_VAO_DAY"</span><span class="token punctuation">,</span><span class="token property">"AWS_SECRET_KEY"</span><span class="token operator">:</span> <span class="token string">"NHAP_SECRET_CUA_BAN_VAO_DAY"</span><span class="token punctuation">}</span> - Tạo một file
makeBucket.js
(cho trùng với lệnh tạo bucket trong aws-cli)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051<span class="token keyword">const</span> <span class="token constant">AWS</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"aws-sdk"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> config <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"./config.json"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> <span class="token constant">REGION</span> <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token constant">REGION</span><span class="token punctuation">;</span><span class="token keyword">const</span> <span class="token constant">ACCESS_KEY</span> <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token constant">AWS_ACCESS_KEY</span><span class="token punctuation">;</span><span class="token keyword">const</span> <span class="token constant">SECRET_KEY</span> <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token constant">AWS_SECRET_KEY</span><span class="token punctuation">;</span><span class="token constant">AWS</span><span class="token punctuation">.</span>config<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">{</span>accessKeyId<span class="token punctuation">:</span> <span class="token constant">ACCESS_KEY</span><span class="token punctuation">,</span>secretAccessKey<span class="token punctuation">:</span> <span class="token constant">SECRET_KEY</span><span class="token punctuation">,</span>region<span class="token punctuation">:</span> <span class="token constant">REGION</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">var</span> s3 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AWS<span class="token punctuation">.</span>S3</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> params <span class="token operator">=</span> <span class="token punctuation">{</span>Bucket<span class="token punctuation">:</span> config<span class="token punctuation">.</span><span class="token constant">BUCKET</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token keyword">const</span> <span class="token function-variable function">editBucketCORS</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span>s3<span class="token punctuation">.</span><span class="token function">putBucketCors</span><span class="token punctuation">(</span><span class="token punctuation">{</span>Bucket<span class="token punctuation">:</span> config<span class="token punctuation">.</span><span class="token constant">BUCKET</span><span class="token punctuation">,</span>CORSConfiguration<span class="token punctuation">:</span> <span class="token punctuation">{</span>CORSRules<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span>AllowedHeaders<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"*"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>AllowedMethods<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"PUT"</span><span class="token punctuation">,</span> <span class="token string">"POST"</span><span class="token punctuation">,</span> <span class="token string">"DELETE"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>AllowedOrigins<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"*"</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">{</span>AllowedMethods<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"GET"</span><span class="token punctuation">]</span><span class="token punctuation">,</span>AllowedOrigins<span class="token punctuation">:</span> <span class="token punctuation">[</span><span class="token string">"*"</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">,</span>err <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">,</span> err<span class="token punctuation">.</span>stack<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">else</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Edit Bucket CORS succeed!`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>s3<span class="token punctuation">.</span><span class="token function">createBucket</span><span class="token punctuation">(</span>params<span class="token punctuation">,</span> <span class="token punctuation">(</span>err<span class="token punctuation">,</span> data<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">,</span> err<span class="token punctuation">.</span>stack<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">else</span> <span class="token punctuation">{</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">editBucketCORS</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> - Cấu trúc thư mục hiện tại đang ntn:12345678.├── config.json├── makeBucket.js├── node_modules├── package.json└── package-lock.json
- File
makeBucket.js
sẽ lấy cấu hình trongconfig.json
và tạo mới một Bucket với têncreated-by-api
. Sau đó chỉnh lại cài đặtCORS
của bucket với hàmeditBucketCORS
. Mình đã thử setup ngay lúc tạo bucket nhưng ko được. Search thử doc thì chỉ có 1 pha edit sau khi đã tạo bucket tại đây thôi.
- Cài đặt gói phụ thuộc
npm i aws-sdk
, cấu hình key chính xác, ta chạy file với:node makeBucket.js
sẽ có output như sau là tạo thành công:1234node makeBucket.js{ Location: 'http://created-by-api.s3.amazonaws.com/' }Edit Bucket CORS succeed! - Ta cũng có thể kiểm tra bằng giao diện web hoặc cli, bằng cli sẽ có output dạng như thế này:12345$ aws s3 ls2020-02-18 23:05:59 craft-created2020-02-22 22:28:01 created-by-api2020-02-22 10:49:55 created-by-cli
- Chỉ chạy 1 file
makeBucket.js
thôi sao phải cấu hình project, config các thứ làm gì? Hãy làm quen với cách quản lý các file cấu hình liên quan tới Key của các dịch vụ như AWS hay Google… một cách là bạn lưu vào file config và add file đó vào trong .gitignore. ( Nếu triển khai trên cloud thì các file cấu hình này nên được lưu vào vùng có mã hóa và hạn chế quyền truy xuất như vậy sẽ an toàn hơn). Sau đó bạn có thể yên tâm đẩy project của mình lên github hoặc share link repo cho người khác. - File .gitignore ntn:123config.jsonnode_modules/
Upload file
Bucket
đã có ta sẽ test upload file lên S3- Tùy thuộc dịch vụ của mình mà chúng ta có các cách upload file lên S3 khác nhau.
Direct upload
- Bài tán thứ nhất: giả sử server của bạn tự tạo
invoice - hóa đơn
khi đó chúng ta cần đẩy trực tiếp file lên S3 và trả về link cho khách hàng xem hóa đơn. - Để server trực tiếp đẩy file lên S3. Chúng ta tạo file
directUpload.js
với nội dung như sau:123456789101112131415161718192021222324252627282930313233<span class="token keyword">const</span> <span class="token constant">AWS</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"aws-sdk"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"fs"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> config <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"./config.json"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> <span class="token constant">BUCKET</span> <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token constant">BUCKET</span><span class="token punctuation">;</span><span class="token keyword">const</span> <span class="token constant">REGION</span> <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token constant">REGION</span><span class="token punctuation">;</span><span class="token keyword">const</span> <span class="token constant">ACCESS_KEY</span> <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token constant">AWS_ACCESS_KEY</span><span class="token punctuation">;</span><span class="token keyword">const</span> <span class="token constant">SECRET_KEY</span> <span class="token operator">=</span> config<span class="token punctuation">.</span><span class="token constant">AWS_SECRET_KEY</span><span class="token punctuation">;</span><span class="token keyword">const</span> localImage <span class="token operator">=</span> <span class="token string">"./cat.jpeg"</span><span class="token punctuation">;</span><span class="token keyword">const</span> imageRemoteName <span class="token operator">=</span> <span class="token template-string"><span class="token string">`directUpload_catImage_</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.jpeg`</span></span><span class="token punctuation">;</span><span class="token constant">AWS</span><span class="token punctuation">.</span>config<span class="token punctuation">.</span><span class="token function">update</span><span class="token punctuation">(</span><span class="token punctuation">{</span>accessKeyId<span class="token punctuation">:</span> <span class="token constant">ACCESS_KEY</span><span class="token punctuation">,</span>secretAccessKey<span class="token punctuation">:</span> <span class="token constant">SECRET_KEY</span><span class="token punctuation">,</span>region<span class="token punctuation">:</span> <span class="token constant">REGION</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">var</span> s3 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">AWS<span class="token punctuation">.</span>S3</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>s3<span class="token punctuation">.</span><span class="token function">putObject</span><span class="token punctuation">(</span><span class="token punctuation">{</span>Bucket<span class="token punctuation">:</span> <span class="token constant">BUCKET</span><span class="token punctuation">,</span>Body<span class="token punctuation">:</span> fs<span class="token punctuation">.</span><span class="token function">readFileSync</span><span class="token punctuation">(</span>localImage<span class="token punctuation">)</span><span class="token punctuation">,</span>Key<span class="token punctuation">:</span> imageRemoteName<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">promise</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span>res <span class="token operator">=></span> <span class="token punctuation">{</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Upload succeeded - `</span></span><span class="token punctuation">,</span> res<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token keyword">catch</span><span class="token punctuation">(</span>err <span class="token operator">=></span> <span class="token punctuation">{</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Upload failed:"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> - Thư mục lúc này thêm 2 file:
directUpload.js
vàcat.jpg
1234567891011.├── cat.jpg├── config.json├── directUpload.js├── makeBucket.js├── node_modules├── package.json└── package-lock.json1 directory, 6 files - Chạy thử chương trình, ok upload ngon lành:123node directUpload.jsUpload succeeded - { ETag: '"550cf35812c2447027f8e4d547a78adb"' }
Upload with signedURL
- Bài toán thứ 2: Ứng dụng của bạn cho phép người dùng tải file trực tiếp lên S3. Lúc này không thể để người dùng tải lên server rồi server lại tải lên S3 được. Thay vì thế Client sẽ call server để lấy 1
signedURL
và client dùng nó để tải file lên S3. - Đầu tiên ở phía server chúng ta tạo 1 file:
uploadWithSignedURL.js
với nội dung như sau:12345678910111213141516171819202122232425262728293031323334353637<span class="token keyword">const</span> cors <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"cors"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> aws <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"aws-sdk"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"express"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> configAWS <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"./config"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>app<span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span><span class="token function">cors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>app<span class="token punctuation">.</span><span class="token keyword">get</span><span class="token punctuation">(</span><span class="token string">"/sign-s3"</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>req<span class="token punctuation">,</span> res<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token keyword">const</span> s3 <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">aws<span class="token punctuation">.</span>S3</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> fileName <span class="token operator">=</span> req<span class="token punctuation">.</span>query<span class="token punctuation">[</span><span class="token string">"file-name"</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">const</span> fileType <span class="token operator">=</span> req<span class="token punctuation">.</span>query<span class="token punctuation">[</span><span class="token string">"file-type"</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">const</span> s3Params <span class="token operator">=</span> <span class="token punctuation">{</span>Bucket<span class="token punctuation">:</span> configAWS<span class="token punctuation">.</span><span class="token constant">BUCKET</span><span class="token punctuation">,</span>Key<span class="token punctuation">:</span> fileName<span class="token punctuation">,</span>Expires<span class="token punctuation">:</span> <span class="token number">60</span><span class="token punctuation">,</span>ContentType<span class="token punctuation">:</span> fileType<span class="token punctuation">,</span><span class="token constant">ACL</span><span class="token punctuation">:</span> <span class="token string">"public-read"</span><span class="token punctuation">}</span><span class="token punctuation">;</span>s3<span class="token punctuation">.</span><span class="token function">getSignedUrl</span><span class="token punctuation">(</span><span class="token string">"putObject"</span><span class="token punctuation">,</span> s3Params<span class="token punctuation">,</span> <span class="token punctuation">(</span>err<span class="token punctuation">,</span> data<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span>err<span class="token punctuation">)</span> <span class="token punctuation">{</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`getSignedUrl error: `</span></span><span class="token punctuation">,</span> err<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">return</span> res<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token keyword">const</span> returnData <span class="token operator">=</span> <span class="token punctuation">{</span>signedRequest<span class="token punctuation">:</span> data<span class="token punctuation">,</span>url<span class="token punctuation">:</span> <span class="token template-string"><span class="token string">`https://</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>configAWS<span class="token punctuation">.</span><span class="token constant">BUCKET</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">.s3.amazonaws.com/</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>fileName<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">}</span><span class="token punctuation">;</span>res<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">stringify</span><span class="token punctuation">(</span>returnData<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>res<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token number">3000</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"come here babe..."</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> - Đoạn server trên làm gì ? Khởi tạo một api nhận request với route
sign-s3
và các query: file-name, file-type. Sau đó request signedURL (vớis3.getSignedUrl
) và trả về cho client. Ok thế là đủ rồi, phần còn lại là của client. - Ở đây mình sẽ tạo một file
ugly-client
index.html
với nội dung như dưới:1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>head</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>head</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>input</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>file<span class="token punctuation">"</span></span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>file-input<span class="token punctuation">"</span></span> <span class="token punctuation">/></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation">=</span><span class="token punctuation">"</span>status<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>Please select a file<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script language-javascript"><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"file-input"</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function-variable function">onchange</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token keyword">const</span> files <span class="token operator">=</span> document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">"file-input"</span><span class="token punctuation">)</span><span class="token punctuation">.</span>files<span class="token punctuation">;</span><span class="token keyword">const</span> file <span class="token operator">=</span> files<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">if</span> <span class="token punctuation">(</span>file <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">return</span> <span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"No file selected."</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token function">getSignedRequest</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> <span class="token function-variable function">getSignedRequest</span> <span class="token operator">=</span> file <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token keyword">const</span> xhr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">XMLHttpRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>xhr<span class="token punctuation">.</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token string">"GET"</span><span class="token punctuation">,</span><span class="token template-string"><span class="token string">`http://localhost:3000/sign-s3?file-name=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>file<span class="token punctuation">.</span>name<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">&file-type=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>file<span class="token punctuation">.</span>type<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>xhr<span class="token punctuation">.</span><span class="token function-variable function">onreadystatechange</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span>xhr<span class="token punctuation">.</span>readyState <span class="token operator">===</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span>xhr<span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token number">200</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token constant">JSON</span><span class="token punctuation">.</span><span class="token function">parse</span><span class="token punctuation">(</span>xhr<span class="token punctuation">.</span>responseText<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">uploadFile</span><span class="token punctuation">(</span>file<span class="token punctuation">,</span> response<span class="token punctuation">.</span>signedRequest<span class="token punctuation">,</span> response<span class="token punctuation">.</span>url<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Could not get signed URL."</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">;</span>xhr<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token keyword">const</span> <span class="token function-variable function">uploadFile</span> <span class="token operator">=</span> <span class="token punctuation">(</span>file<span class="token punctuation">,</span> signedRequest<span class="token punctuation">,</span> url<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token keyword">const</span> xhr <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">XMLHttpRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>xhr<span class="token punctuation">.</span><span class="token function">open</span><span class="token punctuation">(</span><span class="token string">"PUT"</span><span class="token punctuation">,</span> signedRequest<span class="token punctuation">)</span><span class="token punctuation">;</span>xhr<span class="token punctuation">.</span><span class="token function-variable function">onreadystatechange</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span>xhr<span class="token punctuation">.</span>readyState <span class="token operator">===</span> <span class="token number">4</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">if</span> <span class="token punctuation">(</span>xhr<span class="token punctuation">.</span>status <span class="token operator">===</span> <span class="token number">200</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token string">`Upload succeed to: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>url<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span><span class="token function">alert</span><span class="token punctuation">(</span><span class="token string">"Could not upload file."</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">;</span>xhr<span class="token punctuation">.</span><span class="token function">send</span><span class="token punctuation">(</span>file<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span> - Đến đây folder có thêm 2 file mới rồi nha:12345678910111213.├── cat.jpg├── config.json├── directUpload.js├── index.html├── makeBucket.js├── node_modules├── package.json├── package-lock.json└── uploadWithSignedURL.js1 directory, 8 files
- Nói qua một chút. File chỉ có 1 thẻ input để người dùng chọn file.
Script
sẽ lắng ngheonchange
để gửi request tới server bằnggetSignedRequest
. Ở đây mình đang fix cứng URL local như bạn thấy:http://localhost:3000/sign-s3?file-name=${file.name}&file-type=${file.type}
. Sau khi nhận được signedURL do server trả về client sẽ upload file lên S3 bằng:uploadFile
. - Ok! Chạy thử luôn đi. Đầu tiên
npm i express cors
. Chạy server trước:1234node uploadWithSignedURL.jscome here babe... - Sau đó mở file
index.html
bằng chrome và chọn filecat.jpg
chờ một lát kiểm tra trên cửa sổconsole
của browser thấy dạng như dưới là đã upload thành công(nếu thất bại bước nào sẽ bật popup):12Upload succeed to: https://created-by-api.s3.amazonaws.com/cat.jpg - Chắc cú bạn có thể kiểm tra lại trên trang của AWS, hoặc nhanh hơn với aws-cli:1234$ aws s3 ls s3://created-by-api2020-02-24 23:24:19 58836 cat.jpg2020-02-24 23:21:51 58836 directUpload_lovelyCat_1582561310482.jpg
- Như bạn thấy có 2 file 1 file
directUpload
từ server nodejs và 1 file upload từ phía client với signedURL. - Cảm ơn bạn đã theo dõi tới đây! Full code trong bài này có tại đây nhớ đọc qua ReadMe.md một chút nếu có chạy!
- Happy using AWS service!