繁体   English   中英

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

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

我很抱歉发布另一个关于 CORS 的问题,但我就是想不通这个问题。

在此处输入图像描述

我有一个使用 Express.js 服务器(在http://localhost:9001上运行)将图像上传到 Google Cloud 存储桶的 React 应用程序。 即使图像已成功上传,我仍不断收到 CORS 错误,这使我无法返回图像的 URL。 即使图像已上传,我也不太明白如何得到 CORS 错误,但这就是正在发生的事情。

我在谷歌云存储桶上配置了 CORS 如下:

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

当我检查 CORS 错误时,我看到以下内容:

在此处输入图像描述

原点是http://localhost:3000 ,所以配置正确,我正在使用POST上传图像,因此也应该允许。

我写的上传图片的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);
        });
}

我已将标头注释掉,因为它们不断抛出Multipart: Boundary not found错误,我已经看到其他人对此有疑问,并且删除标头设置并没有引起任何其他问题。

我在将图像上传到 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)
})

以下是我的 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!')
    })  

我已经尝试了很多不同的方法来让它工作:

  1. 我尝试将 http://localhost:9001 添加到 CORS 配置以及其他 URL
  2. 我试过用"*"打开所有来源
  3. 我已经阅读了所有文档[here][3]
  4. 我已尝试遵循 Google 此处的所有故障排除文档
  5. 我已经清除了我的浏览器缓存,因为我已经看到这可能导致 CORS 错误持续存在 - 请参阅此处的另一篇文章
  6. 我已经尝试过一夜等待我的 Google Cloud CORS 配置生效,因为我听说配置可能需要一些时间才能传播

尽管如此,我仍然收到 CORS 错误,但我的上传仍在工作。 我只需要清除错误,就可以获得返回的图像 URL。

您将 cors 添加到 Google Cloud 存储桶,但您忘记将其添加到快递服务器 POST function。 或者在您的快递服务器上将其用作全局。

在您的快递 POST function 上试试这个:

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

或者

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

甚至更好:

    /* 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