簡體   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