Загрузка изображений из AWS S3 через Lambda и API Gateway - с использованием класса fetch - PullRequest
0 голосов
/ 15 сентября 2018

Я пытаюсь использовать API выборки JavaScript , AWS API Gateway , AWS Lambda и AWS S3 для созданиясервис, который позволяет пользователям загружать и скачивать медиа.Сервер использует NodeJs 8.10;браузер - Google Chrome версии 69.0.3497.92 (официальная сборка) (64-разрядная версия).

В долгосрочной перспективе допустимые носители будут включать в себя аудио, видео и изображения.На данный момент я был бы рад просто заставить изображения работать.

Проблема, с которой я столкнулся: мой клиент на стороне браузера, реализованный с использованием fetch, может загружать JPEG в S3 через API Gateway и Lambda.просто хорошо.Я могу использовать curl или консоль S3, чтобы загрузить JPEG из моей корзины S3, а затем просмотреть изображение в средстве просмотра изображений.

Но, если я попытаюсь загрузить изображение через браузер,на стороне клиента и выборки, я не получаю ничего, что я могу отобразить в браузере.

Вот код от клиента на стороне браузера:

fetch(
  'path/to/resource',
  {
    method: 'post',
    mode: "cors",
    body: an_instance_of_file_from_an_html_file_input_tag,
    headers: {
      Authorization: user_credentials,
      'Content-Type': 'image/jpeg',
    },
  }
).then((response) => {
  return response.blob();
}).then((blob) => {
  const img = new Image();
  img.src = URL.createObjectURL(blob);
  document.body.appendChild(img);
}).catch((error) => {
  console.error('upload failed',error);
});

Вот код на стороне сервера, используя Claudia.js :

const AWS = require('aws-sdk');
const ApiBuilder = require('claudia-api-builder');
const api = new ApiBuilder();

api.corsOrigin(allowed_origin);
api.registerAuthorizer('my authorizer', {
  providerARNs: ['arn of my cognito user pool']
});

api.get(
  '/media',
  (request) => {
    'use strict';

    const s3 = new AWS.S3();
    const params = {
      Bucket: 'name of my bucket', 
      Key: 'name of an object that is confirmed to exist in the bucket and to be properly encoded as and readable as a JPEG',
    };
    return s3.getObject(params).promise().then((response) => {
       return response.Body;
     })
    ;
  }
);

module.exports = api;

Вот начальные OPTION заголовки запроса и ответа на сетевой панели Chrome:

OPTIONS headers, one of two OPTIONS headers, two of two

Вот следующие GET заголовки запросов и ответов:

GET headers, one of two GET headers, two of two

Что меня интересует, так это то, что размер изображения сообщается как 699873 (без единиц) в консоли S3, но тело ответа транзакции GET сообщается в Chrome примерно на 2,5 МБ (опять же,без единиц измерения).

Полученное изображение представляет собой квадрат 16х16 с мертвой ссылкой.Я не получаю никаких ошибок или предупреждений в консоли браузера или CloudWatch.

Я много чего пробовал;было бы интересно услышать, что кто-то там может придумать.

Заранее спасибо.

РЕДАКТИРОВАТЬ: В Chrome:

console work showing conversion of fetch response to text representing a JSON-encoded Buffer

1 Ответ

0 голосов
/ 15 сентября 2018

Клаудия требует, чтобы клиент указал, какой тип MIME он будет принимать для двоичных полезных нагрузок. Итак, сохраните конфигурацию 'Content-type' в объекте headers на стороне клиента:

fetch(
  'path/to/resource',
  {
    method: 'post',
    mode: "cors",
    body: an_instance_of_file_from_an_html_file_input_tag,
    headers: {
      Authorization: user_credentials,
      'Content-Type': 'image/jpeg', // <-- This is important.
    },
  }
).then((response) => {
  return response.blob();
}).then((blob) => {
  const img = new Image();
  img.src = URL.createObjectURL(blob);
  document.body.appendChild(img);
}).catch((error) => {
  console.error('upload failed',error);
});

Затем на стороне сервера вы должны сообщить Клаудии, что ответ должен быть двоичным и какой тип MIME использовать:

const AWS = require('aws-sdk');
const ApiBuilder = require('claudia-api-builder');
const api = new ApiBuilder();

api.corsOrigin(allowed_origin);
api.registerAuthorizer('my authorizer', {
  providerARNs: ['arn of my cognito user pool']
});

api.get(
  '/media',
  (request) => {
    'use strict';

    const s3 = new AWS.S3();
    const params = {
      Bucket: 'name of my bucket', 
      Key: 'name of an object that is confirmed to exist in the bucket and to be properly encoded as and readable as a JPEG',
    };
    return s3.getObject(params).promise().then((response) => {
       return response.Body;
     })
    ;
  },
  /** Add this. **/
  {
    success: { 
      contentType: 'image/jpeg', 
      contentHandling: 'CONVERT_TO_BINARY', 
    }, 
  }
);

module.exports = api;
...