Ошибки CORS с бэкэндом Express Node.JS, интерфейсом React и инфраструктурой AWS - PullRequest
0 голосов
/ 25 июня 2019

У меня есть интерфейс React, который позволяет пользователям добавлять и просматривать рецепты, которые содержат текст и изображение.Бэкэнд представляет собой приложение Express Node.JS, которое выполняет чтение и запись в базу данных DynamoDB.Приложение развертывается на AWS с использованием Serverless Framework, поэтому оно использует API Gateway, Lambda, DynamoDB и S3 для хранения фотографий.Я работаю над тем, чтобы заставить работать маршрут загрузки фото, но ошибки CORS мешают ему работать.

Я импортировал модуль cors NPM и использую его в приложении.Я попытался подробно указать происхождение в конфигурации, но это не имеет значения.У меня также есть cors: true на каждом маршруте в моем файле serverless.yml.

serverless.yml excerpt:
service: recipes-api

provider:
  name: aws
  runtime: nodejs8.10
  stage: dev
  region: us-east-1
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:Query
        - dynamodb:Scan
        - dynamodb:GetItem
        - dynamodb:PutItem
        - dynamodb:UpdateItem
        - dynamodb:DeleteItem
      Resource:
        - { "Fn::GetAtt": ["RecipesDynamoDBTable", "Arn"] }
  environment:
    RECIPES_TABLE: ${self:custom.tableName}
    S3_BUCKET: ${self:custom.bucketName}

functions:
  app:
    handler: index.handler
    events:
      - http: ANY /
      - http: 'ANY {proxy+}'
  getRecipe:
    handler: index.handler
    events:
      - http: 
         path: recipes/{name}
         method: get
         cors: true
  allRecipes:
    handler: index.handler
    events:
      - http:
         path: allrecipes
         method: get
         cors: true
  addRecipe:
    handler: index.handler
    events:
      - http:
         path: recipes
         method: post
         cors: true
  uploadPhoto:
    handler: index.handler
    events:
      - http:
         path: uploadphoto
         method: post
         cors: true
  getPhoto:
    handler: index.handler
    events:
      - http:
         path: photo/{name}
         method: get
         cors: true

index.js excerpt:
const serverless = require('serverless-http');
const express = require('express');
const app = express();
const AWS = require('aws-sdk');
const cors = require('cors');
...
app.use(cors({origin: 'https://recipes.example.co'}))
//Upload Photo Endpoint
app.post('/uploadphoto', function (req, res) {
    const s3 = new AWS.S3();  // Create a new instance of S3
    const fileName = req.body.fileName;
    const fileType = req.body.fileType;

    const s3Params = {
        Bucket: S3_BUCKET,
        Key: fileName,
        Expires: 500,
        ContentType: fileType,
        ACL: 'public-read'
    };

    s3.getSignedUrl('putObject', s3Params, (err, data) => {
        if(err){
            console.log(err);
            res.json({success: false, error: err})
        }
    // Data payload of what we are sending back, the url of the signedRequest and a URL where we can access the content after its saved. 
        const returnData = {
            signedRequest: data,
            url: `https://${S3_BUCKET}.s3.amazonaws.com/${fileName}`
        };
    // Send it all back
        res.json({success:true, data:{returnData}});
  });

})

AddRecipeForm.js excerpt:
handleUpload = (ev) => {
    console.log("handleUpload")
    console.log(ev)
    let file = this.uploadInput.files[0];
    // Split the filename to get the name and type
    let fileParts = this.uploadInput.files[0].name.split('.');
    let fileName = fileParts[0];
    let fileType = fileParts[1];
    console.log("Preparing the upload");
    axios.post("https://bqdu4plthq.execute-api.us-east-1.amazonaws.com/dev/uploadphoto",{
      fileName : fileName,
      fileType : fileType
    })
    .then(response => {
      var returnData = response.data.data.returnData;
      var signedRequest = returnData.signedRequest;
      var url = returnData.url;
      this.setState({url: url})
      console.log("Recieved a signed request " + signedRequest);

     // Put the fileType in the headers for the upload
      var options = {
        headers: {
          'Content-Type': fileType
        }
      };
      axios.put(signedRequest,file,options)
      .then(result => {
        console.log("Response from s3")
        this.setState({success: true});
      })
      .catch(error => {
        console.error(error);
      })
    })
    .catch(error => {
      console.error(error);
    })
  }

При нажатии кнопки «Загрузить фото», которая вызывает функцию handleUpload в AddRecipeForm.js, в моей консоли появляются следующие ошибки:

Origin https://recipes.example.co is not allowed by Access-Control-Allow-Origin.

XMLHttpRequest cannot load https://bqdu4plthq.execute-api.us-east-1.amazonaws.com/dev/uploadphoto due to access control checks.

Failed to load resource: Origin https://recipes.example.co is not allowed by Access-Control-Allow-Origin.

Обратите внимание, что работает любой другой маршрут (getRecipe, allRecipes, addRecipe) и отправляет заголовки CORS, поэтому я не уверен, почему мой запрос addphoto из React в API Gateway не отправляет заголовки CORS, даже если он должен использовать его в index.js.Заранее спасибо за помощь!

1 Ответ

0 голосов
/ 25 июня 2019

Ваш serverless.yml имеет определенную по умолчанию функцию 'app', которая является универсальным маршрутом ({proxy +} соответствует всем).Похоже, что это маршрут, по которому вы переходите, а не uploadPhoto, потому что ваш маршрут uploadPhoto определен как метод POST, но ваш запрос axios внешнего интерфейса использует PUT.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...