Nodejs: Put file lên AWS S3 từ trình đuyệt của bạn - không qua server

Đặt vấn đề

Vấn đề mình muốn đề cập hôm nay là về tốc độ xử lý khi upload 1 file lên AWS S3. Cụ thể với cách xử lý thông thường sau khi chọn ảnh từ local chúng ta thực hiện upload ảnh đó lên server sau đó là đẩy lên S3.
Mục tiêu của chúng ta là upload một file lên S3, tuy nhiên lại phải qua một bước là đưa lên server dẫn đến tốn thời gian xử lý, tốn băng thông cũng như khả năng lưu trữ của server.
Để giải quyết vấn đề trên AWS đã cung cấp 1 cơ chế đó là chúng ta có thể dùng 1 URL (pre signed url) đã được ủy quyền để có thể put, get, delete,... một file trên S3 mà không cần xử lý qua server. Nghĩa là khi chúng ta có URL đó chúng ta có thể thực hiện trực tiếp từ phía client các thao tác để tác động đến một object trên S3.

Giải pháp

Ví dụ khi chúng ta cần upload một file lên S3, luồng xử lý sẽ như sau:

  1. Người dùng click chọn file từ máy local
  2. Thay vì post file lên server để xử lý sau đó từ server gửi file lên S3 thì chúng ta gửi một request đến AWS yêu cầu cấp quyền put file lên S3, cụ thể trường hợp này là yêu cầu AWS gửi cho chúng ta một URL mà chúng ta có thể dùng nó để upload file lên S3.
  3. Sau khi URL được tạo ra, AWS sẽ gửi lại cho chúng ta. Tất nhiên chỉ user được ủy quyền mới có quyền sử dụng url này.
  4. Sau khi nhận được URL này chúng ta có thể sử dụng nó để upload file lên S3 mà không cần phải authen với AWS nữa.

Cài đặt source code

Không chần chờ gì nữa, mình sẽ đi vào cài đặt source code nhé. Ở đây mình dùng NodeJS.
Các bạn có thể tham khảo thêm chức năng trên với code PHP ở đây

  • Đến thư mục root của project, tạo file app.js
    const express = require('express');
    const app = express();
    const port = 3000; // set port cho app
    app.use('/', express.static(__dirname + '/public'));  
  • Cài đặt module express: npm install express
  • Tạo layout form upload

    // homepage route (app.js)

    app.get('/', function(req, res){
       res.render('index.html');
    });
    

    // file view cho form upload (file public/index.html)

    <form action="/upload" enctype="multipart/form-data" method="POST">
       <input type="file" id="fileInput" name="fileInput" />
       <input type="button" id="button" value="Upload Photo"/>
       <br /><br />
       Url:<a href="" target="_blank" class="new_url"></a><br /><br />
    </form>
    

    // Tạo JS để xử lý file khi click button upload (file public/index.html)

    $(document).ready(function() {
     $('#button').click(function() {
         var files = $('#fileInput').prop('files')[0];
         var filename = "new_" +files.name;
         var fd = new FormData();
         fd.append( 'file', files );
         var contentType = files.type;
         $.get('http://localhost:3000/generatepresignedurl?fileName='+filename+'&type='+contentType, function(signedUrl) {
             $.ajax({
                 url: signedUrl,
                 type: 'PUT',
                 dataType: 'html',
                 processData: false,
                 headers: {'Content-Type': contentType},
                 crossDomain: true,
                 data: files
             }).done(function(data,textStatus,error) {
                 $(".new_url").html('https://s3-trungnv.s3.amazonaws.com/'+filename);
                 $(".new_url").attr("href",'https://s3-trungnv.s3.amazonaws.com/'+filename);
             }).fail(function (jqXHR, textStatus, errorThrown) {
                 alert("Error!");
             });
         });
        });
    });
    
  • Run server (file app.js)

    app.listen(port,function(){
       console.log('Server listening on port ' + port);
    });
    
  • Sau khi hoàn thành xong bước 7 chúng ta mở terminal và chạy: node app.js

  • Sau đó mở trình duyệt và gõ: http:/localhost:3000 chúng ta sẽ thấy giao diện như sau:
    alt text

  • Tiếp theo chúng ta cài đặt thư viện aws javascript cho nodejs.

  • Mở Termial và run: npm install aws-sdk

  • Include thư viện aws và khởi tạo S3 object (file app.js)

    const AWS = require('aws-sdk');
    const s3Object = new AWS.S3({
       accessKeyId : config.aws_access_key_id,
       secretAccessKey : config.aws_secret_access_key,
       region: config.aws_region,
    });
    
  • Tạo request để tạo ra pre signed url như sau (app.js).

    app.get('/generatepresignedurl',function(req,res){
       var fileName = req.query.fileName;
       var type = req.query.type;
       var url = s3Object.getSignedUrl('putObject', {
           Bucket: config.bucket,
           Key: fileName,
           Expires: config.signedUrlExpireSeconds,
           ACL: "public-read",
           ContentType: type
       });
       res.send(url);
    });
    
  • Tiếp theo chúng ta cài phân quyền cho bucket ở S3 để có thể put file bằng cách truy cập vào S3 BucketName =>Permissions => CORS configuration và add nội dung như dưới đây và save lại.

    <?xml version="1.0" encoding="UTF-8"?>
    <CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <AllowedMethod>HEAD</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
    </CORSConfiguration>
    
    • Bước cuối cùng chúng ta mở trình duyệt và check kết quả. Mình thử chọn 1 bức ảnh và click apload
      // kết quả alt text
  • Các bạn có thể tham khảo thêm source code ở đây

Bình luận


White
{{ comment.user.name }}
Bỏ hay Hay
{{comment.like_count}}
Male avatar
{{ comment_error }}
Hủy
   

Hiển thị thử

Chỉnh sửa

Male avatar

Trung Nguyen

1 bài viết.
0 người follow
Kipalog
{{userFollowed ? 'Following' : 'Follow'}}
Bài viết liên quan
White
1 1
Transfer files từ local computer đến AWS EC2 dùng FileZilla Bài toán: Làm thế nào để copy files từ local computer đến AWS EC2? Cách làm: Có mấy ...
Minh-Trung Nguyễn viết 7 tháng trước
1 1
White
2 0
Bài viết gốc có ở blog của mình: (Link) Trong bài viết này, mình muốn giới thiệu về module trong terraform, và cách sử dụng nó để deploy lên nhiều...
Chiến Kira viết 2 tháng trước
2 0
{{like_count}}

kipalog

{{ comment_count }}

bình luận

{{liked ? "Đã kipalog" : "Kipalog"}}


Male avatar
{{userFollowed ? 'Following' : 'Follow'}}
1 bài viết.
0 người follow

 Đầu mục bài viết

Vẫn còn nữa! x

Kipalog vẫn còn rất nhiều bài viết hay và chủ đề thú vị chờ bạn khám phá!