简体   繁体   English

React.js、Express.js 和可怕的 CORS

[英]React.js, Express.js and the dreaded CORS

I'm sorry to be posting yet another question about CORS but I just can't figure this one out.我很抱歉发布另一个关于 CORS 的问题,但我就是想不通这个问题。

在此处输入图像描述

I have a React app using an Express.js server (running on http://localhost:9001 ) to upload an image to a Google Cloud storage bucket.我有一个使用 Express.js 服务器(在http://localhost:9001上运行)将图像上传到 Google Cloud 存储桶的 React 应用程序。 I keep getting a CORS error even though the image is uploaded successfully and this is preventing me from getting the image's URL returned.即使图像已成功上传,我仍不断收到 CORS 错误,这使我无法返回图像的 URL。 I don't really understand how I can get a CORS error even though the image is uploaded but that's what's happening.即使图像已上传,我也不太明白如何得到 CORS 错误,但这就是正在发生的事情。

I have configured CORS on the Google Cloud storage bucket as follows:我在谷歌云存储桶上配置了 CORS 如下:

[
    {
      "origin": ["http://localhost:3000"],
      "responseHeader": "*",
      "method": ["POST"],
      "maxAgeSeconds": 3600
    }
]

When I inspect the CORS error I'm getting I see the following:当我检查 CORS 错误时,我看到以下内容:

在此处输入图像描述

The origin is http://localhost:3000 , so that's configured correctly and I'm using POST to upload the image so that should be allowed as well.原点是http://localhost:3000 ,所以配置正确,我正在使用POST上传图像,因此也应该允许。

The function I've written to upload the image is as follows:我写的上传图片的function如下:

function postImage(file) {
    const formData = new FormData();
    formData.append('file', file);

    fetch(`${window.location.protocol}//${window.location.hostname}:9001/uploads`, {
        method: 'POST',
        mode: 'cors',
        cache: 'no-cache',
        // headers: {
        //     'Content-Type': 'multipart/form-data'
        // },
        body: formData
    })
        // .then((response) => response.json())
        .then((response) => console.log('This is your data:', response.data))

        .catch(error => {
            console.error('There has been a problem uploading your image', error);
        });
}

I've commented out the headers as including them kept throwing up a Multipart: Boundary not found error that I've seen others have an issue with and removing the headers setting hasn't caused any other issues.我已将标头注释掉,因为它们不断抛出Multipart: Boundary not found错误,我已经看到其他人对此有疑问,并且删除标头设置并没有引起任何其他问题。

I have a helper function on the Express server that uploads the image to the Google Cloud storage bucket:我在将图像上传到 Google Cloud 存储桶的 Express 服务器上有一个助手 function:

const uploadImage = (file) => new Promise((resolve, reject) => {
    const { originalname, buffer } = file

    const blob = bucket.file(originalname.replace(/ /g, "_"))
    const filetype = blob.name.split('.').pop()
    const filename = `${uuidv4()}.${filetype}`
    const blobStream = blob.createWriteStream({
        resumable: false
    })
    blobStream.on('finish', () => {
        const publicUrl = format(
            `https://storage.googleapis.com/${bucket.name}/${filename}`
        )
        resolve(publicUrl)
    })
        .on('error', () => {
            reject(`Unable to upload image, something went wrong`)
        })
        .end(buffer)
})

Here are the functions on my Express server:以下是我的 Express 服务器上的功能:

import { typeDefs } from './graphql-schema'
import { ApolloServer } from 'apollo-server-express'
import express from 'express'
import neo4j from 'neo4j-driver'
import { makeAugmentedSchema } from 'neo4j-graphql-js'
import dotenv from 'dotenv'
import { initializeDatabase } from './initialize'
const bodyParser = require('body-parser')
const multer = require('multer')
const uploadImage = require('./helpers/helpers')

dotenv.config()

const app = express()

    const schema = makeAugmentedSchema({
      typeDefs,
      config: {
        query: {
          exclude: ['RatingCount'],
        },
        mutation: {
          exclude: ['RatingCount'],
        },
      },
    })
    
    const driver = neo4j.driver(
      process.env.NEO4J_URI,
      neo4j.auth.basic(
        process.env.NEO4J_USER,
        process.env.NEO4J_PASSWORD
      ),
      {
        encrypted: process.env.NEO4J_ENCRYPTED ? 'ENCRYPTION_ON' : 'ENCRYPTION_OFF',
      }
    )
    
    const init = async (driver) => {
      await initializeDatabase(driver)
    }
    
    init(driver)
    
    const server = new ApolloServer({
      context: { driver, neo4jDatabase: process.env.NEO4J_DATABASE },
      schema: schema,
      introspection: true,
      playground: true,
    })
    
    // Specify host, port and path for GraphQL endpoint
    const port = process.env.GRAPHQL_SERVER_PORT || 4001
    const path = process.env.GRAPHQL_SERVER_PATH || '/graphql'
    const host = process.env.GRAPHQL_SERVER_HOST || '0.0.0.0'
    
    
    // Code for uploading files to Google Cloud
    app.use((req, res, next, err) => {
      console.error(err.stack)
      res.header("Access-Control-Allow-Origin", "*");
      res.type('multipart/form-data')
      res.status(500).json({
        error: err,
        message: 'Internal server error!',
      })
      next()
    })
    
    const multerMid = multer({
      storage: multer.memoryStorage(),
      limits: {
        // no larger than 5mb.
        fileSize: 5 * 1024 * 1024,
      },
    })
    
    app.disable('x-powered-by')
    app.use(multerMid.single('file'))
    app.use(bodyParser.json())
    app.use(bodyParser.urlencoded({ extended: false }))
    
    app.post('/uploads', async (req, res, next) => {
      try {
        const myFile = req.file
        const imageUrl = await uploadImage(myFile)
        res
          .status(200)
          .json({
            message: "Upload was successful",
            data: imageUrl
          })
      } catch (error) {
        next(error)
      }
    })

    server.applyMiddleware({ app, path })
    
    app.listen({ host, port, path }, () => {
      console.log(`GraphQL server ready at http://${host}:${port}${path}`)
    })
    
    app.listen(9001, () => {
      console.log('Node.js -> GCP server now listening for requests!')
    })  

I've tried a lot of different things to get this working:我已经尝试了很多不同的方法来让它工作:

  1. I've tried adding http://localhost:9001 to the CORS configuration, as well as other URLs我尝试将 http://localhost:9001 添加到 CORS 配置以及其他 URL
  2. I've tried opening up all origins with "*" for我试过用"*"打开所有来源
  3. I've read through all the documentation [here][3]我已经阅读了所有文档[here][3]
  4. I've tried following all the troubleshooting documentation Google has here我已尝试遵循 Google 此处的所有故障排除文档
  5. I've cleared my browser cache as I've seen that can cause the CORS errors to persist - see another post here我已经清除了我的浏览器缓存,因为我已经看到这可能导致 CORS 错误持续存在 - 请参阅此处的另一篇文章
  6. I've tried waiting over night for my Google Cloud CORS configuration to take effect as I've heard the configuration can take a bit of time to propagate我已经尝试过一夜等待我的 Google Cloud CORS 配置生效,因为我听说配置可能需要一些时间才能传播

Despite all of this I'm still getting the CORS error but my upload is still working.尽管如此,我仍然收到 CORS 错误,但我的上传仍在工作。 I just need to clear the error so I can get the returned image URL.我只需要清除错误,就可以获得返回的图像 URL。

You add cors to Google Cloud storage bucket but you forgot to add it to express server POST function.您将 cors 添加到 Google Cloud 存储桶,但您忘记将其添加到快递服务器 POST function。 Or use it as global on your express server.或者在您的快递服务器上将其用作全局。

Try this on your express POST function:在您的快递 POST function 上试试这个:

res.header("Access-Control-Allow-Origin", "http://example.com");

Or或者

res.header("Access-Control-Allow-Origin", "*");

Or even better:甚至更好:

    /* Headers */
app.use((req, res, next) => {
    res.header("Access-Control-Allow-Origin", "*"); // update to match the domain you will make the request from
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM