Извините, что задаю еще один вопрос о 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. 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. I don't really understand how I can get a CORS error even though the image is uploaded but that's what's happening.
I have configured CORS on the Google Cloud storage bucket as follows:
[
{
"origin": ["http://localhost:3000"],
"responseHeader": "*",
"method": ["POST"],
"maxAgeSeconds": 3600
}
]
When I inspect the CORS error I'm getting I see the following:
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.
The function I've written to upload the image is as follows:
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.
I have a helper function on the Express server that uploads the image to the Google Cloud storage bucket:
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:
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:
- I've tried adding http://localhost:9001 to the CORS configuration, as well as other URLs
- I've tried opening up all origins with
"*"
for
- I've read through all the documentation
[here][3]
- I've tried following all the troubleshooting documentation Google has здесь
- Я очистил кеш своего браузера, поскольку видел, что это может привести к сохранению ошибок CORS - см. Другой пост здесь
- Я пробовал подождать ночь своего Google Cloud CORS конфигурация вступила в силу, поскольку я слышал, что для распространения конфигурации может потребоваться некоторое время.
Несмотря на все это, я все еще получаю ошибку CORS, но моя загрузка все еще работает. Мне просто нужно сбросить ошибку, чтобы получить URL-адрес возвращенного изображения.