Search code examples
node.jsamazon-web-servicesexpressherokucors

CORS error on some GET requests, but not all?


I have a configurator that I am able to change size and color of a piece of furniture using Google's . I have it working great on localhost, but for some reason, when deploying my MERN project to Heroku, I keep getting CORS errors when I go to swap the materials? I am able to GET some of the textures no problem, but other's I'm getting the CORS error.

All materials/images come from the same S3 bucket, and has the correct CORS policy on AWS. And in my Server.js file I have app.useCors(()); middleware installed. Really confused as to why I can GET some items, but not all from the same S3 bucket.

The CORS error in example: Access to image at 'https://scoutmaterials.s3.us-east-2.amazonaws.com/Lacquer/Lacquer_Nrm.jpg' from origin 'https://fathomless-brook-11892.herokuapp.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

I have it set up to where when a user "clicks" on a label it will then fire an event to "swap" the materials.

Here is the swatch layout (the images in value, data-value, data-value2 are the images I'm getting from the S3 bucket):

<div key={index} className='swatch-container'>
    <input type="radio" name={`properties[${names[1]} Finish]`} id={`${names[1]} Finish[${item.name}]`} className='variant__input' value={item.name} defaultChecked={item === selectedInput} onChange={(event) => {setSelectedInput(event.target.value); document.querySelectorAll(`#${names[1]}`).forEach(label => label.classList.remove("selected")); event.target.parentNode.querySelector("label").classList.add("selected");}}></input>
    <label 
        onClick={(e) => {
        if(names[1] === 'Body'){
        swapBody(e)
        }
        if(names[1] === 'Drawer'){
        swapDrawers(e)
        }
        }} 
        className='material__button-label' 
        htmlFor={`${names[1]} Finish[${item.name}]`}
        id={names[1]}
        value={item.diffuse} 
        data-value={item.normal}
        data-value2={item.orm}
        style={{backgroundImage:`url(${item.thumbnail})`}}
        crossorigin='use-credentials'
    ></label>
    <div id='materialName'>{item.name}</div>
</div>

Here is the swapping code:

const swapBody = (event) => {
const modelViewer = document.querySelector('model-viewer#model-viewer')
const material = modelViewer.model.getMaterialByName('Body');

const diffuseSwap = async (channel) => {
    const diffuse = await modelViewer.createTexture(event.target.getAttribute('value'));
    if (channel.includes('base')) 
    {
        material.pbrMetallicRoughness[channel].setTexture(diffuse);
    }
}
                
const normalSwap = async (channel) => {
    const normal = await modelViewer.createTexture(event.target.getAttribute('data-value'));
    if (channel.includes('normal')) 
    {
        material[channel].setTexture(normal);
    }
}
                
const ORMSwap = async (channel) => {
    const ORM = await modelViewer.createTexture(event.target.getAttribute('data-value2'));
    if (channel.includes('metallic')) 
    {
        material.pbrMetallicRoughness[channel].setTexture(ORM);
    }
}
  
diffuseSwap('baseColorTexture');
normalSwap('normalTexture');
ORMSwap('metallicRoughnessTexture');
console.log("swapping material")
};

And finally my Server.js code, with the added cors() middleware:

require("dotenv").config();
const path = require('path');
const express = require("express");
const cors = require('cors');
const productRoutes = require("./server/routes/productRoutes");
const connectDB = require("./server/config/db");
const mongoose = require("mongoose");
const bodyParser = require('body-parser');
const Product = require('./server/models/Product')

connectDB();

const app = express();

const corsOptions = {
    origin: "*",
    methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
    preflightContinue: false,
    optionsSuccessStatus: 204
  };

app.use(cors(corsOptions));
app.use(express.json());
app.use(bodyParser.json());

const AR = mongoose.model('AR', arSchema);

app.use("/api/products", productRoutes);


if(process.env.NODE_ENV === "production"){
    app.use(express.static(path.join(__dirname, '/client/build')));

    app.get('*', (req, res) => {
        res.sendFile(path.join(__dirname, 'client', 'build', 'index.html'));
    })
} else {
    app.get('/', (req, res) => {
        res.send('API running...');
    });
}


// const PORT = process.env.PORT || 5000;
const PORT = process.env.PORT;
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));


Solution

  • @jub0bs lead me in the right direction. After digging around some more I found out that simply changing these values:

    value={item.diffuse}
    data-value={item.normal}
    data-value2={item.orm}
    

    To this:

    value={`${item.diffuse}`} 
    data-value={`${item.normal}`}
    data-value2={`${item.orm}`}
    

    Not exactly sure what this does, but from my understanding it formats it to a string? Which would make since because it's supposed to be a URL, not a JS function.