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

Я пытаюсь использовать 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:

ВАРИАНТЫ заголовков, один из двух ВАРИАНТЫ заголовков, два из двух

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

ПОЛУЧИТЕ заголовки, один из двух ПОЛУЧИТЬ заголовки, два из двух

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

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

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

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

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

консольная работа, показывающая преобразование ответа выборки в текст, представляющий закодированный в JSON буфер

1 ответ

Решение

Клаудия требует, чтобы клиент указал, какой тип 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);
});

Затем на стороне сервера вы должны сообщить Claudia, что ответ должен быть двоичным и какой тип 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;
Другие вопросы по тегам