cross origin resource policy issue when playing files from s3 on deployed app
Asked Answered
D

2

5

I have a deployed app on Heroku that allows me to play audio files. You can check it out here https://telecurve.herokuapp.com/manage. Before I had no issues playing the files in Heroku but after I modified my server.js file (my app is an Express app that is deployed with a built Create React app), I get this error. You can try playing an audio file and seeing the response. However, I am still able to download files from s3 with the download button and have no issues.

Here is some relevant code:

server.js

    require('rootpath')();
    const path = require('path');
    const express = require('express');
    const app = express();
    const bodyParser = require('body-parser');
    const cookieParser = require('cookie-parser');
    const cors = require('cors');
    
    app.use(bodyParser.urlencoded({ extended: false }));
    app.use(bodyParser.json());
    app.use(cookieParser());
    
    // Have Node serve the files for our built React app
    app.use(express.static(path.resolve(__dirname, 'build')));
    
    // allow cors requests from any origin and with credentials
    app.use(cors({ origin: (origin, callback) => callback(null, true), credentials: true }));
    
   //change added that caused issues with the playing mechanism. Needed these headers for another 
    app.use(function(req, res, next) {
      res.header("Cross-Origin-Embedder-Policy", "require-corp");
      res.header("Cross-Origin-Opener-Policy", "same-origin");
      next();
    });
    
    
    // file api routes
    app.use('/accounts', require('./accounts/accounts.controller'));
    
    
    // All other GET requests not handled before will return our React app
    app.get('*', (req, res) => {
        res.sendFile(path.resolve(__dirname, 'build', 'index.html'));
    });
    
    app.get('/app', async (req, res) => {
      res.sendFile(path.join(__dirname, 'public/index.html'));
    });
    // does work, cors headers in response as expected
    
    
    // start server
    const port = process.env.PORT || 2000;
    app.listen(port, () => console.log('Server listening on port ' + port));

this is the particular change in server.js that I added:

   //change added that caused issues with the playing mechanism. Needed these headers for another 
    app.use(function(req, res, next) {
      res.header("Cross-Origin-Embedder-Policy", "require-corp");
      res.header("Cross-Origin-Opener-Policy", "same-origin");
      next();
    });

Maybe I need to add an additional header for s3?

I also recently removed this code:

app.use(function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
});

Here is my presigning method in the backend that I use to generate urls to play/download from:

  const customer_id = data['customer-id'];
  const sound_id = data['sound-id'];
  
  return new Promise((resolve, reject) => {
    //get presigned url

    var myBucket = process.env.NODE_APP_BUCKET_NAME;
    var myKey = "sounds/" + customer_id + "/" + sound_id + ".wav"; 
    const signedUrlExpireSeconds = 120;
    try {
      const url = s3.getSignedUrl('getObject', {
        Bucket: myBucket,
        Key: myKey,
        ResponseContentDisposition: 'attachment',
        Expires: signedUrlExpireSeconds
      });
      resolve(url)
    }
    catch {
      console.log('S3 Object does not exist');
      resolve('');
    }
  });

I then take this url, create a new audio object with var audio = new Audio(url) and play it.

Let me know if you see anything going wrong or if im missing anything.

Damselfly answered 30/7, 2021 at 13:3 Comment(0)
T
6

You seem to directly use the URL pointing at your audio file on S3, meaning that:

Your app was down when I wrote this, so I couldn't actually validate it's caused by S3 cross-origin resources, but based on your question, it is the most likely issue.

Tarweed answered 4/8, 2021 at 16:37 Comment(0)
O
0

got into the same issue.

here how it is resolved:

const audio = "your audio tag";
const audio_src = audio.src;
fetch(audio_src, { mode: 'cors' })
    .then(response => response.blob())
    .then(blob => {
        const url = URL.createObjectURL(blob);
        audio.src = url;
        audio.play();
    })
    .catch(error => console.error('Error fetching audio:', error));
Outofdoors answered 30/8 at 12:35 Comment(1)
This answer that is largely code could be improved with an explanation as to where to make the change. The code excerpts in the original question do not call a createObjectURL or play method, nor have a variable called audio, so it's not immediately clear what to change.Disarrange

© 2022 - 2024 — McMap. All rights reserved.