简体   繁体   English

阿波罗服务器快递 CORS 问题

[英]apollo-server-express CORS issue

So I am migrating to apollo-server-express 2.3.3 ( I was using 1.3.6 ) I've followed several guides, making the necessary tweaks but am stuck in a CORS issue.所以我正在迁移到 apollo-server-express 2.3.3 (我使用的是 1.3.6 )我遵循了几个指南,进行了必要的调整,但陷入了 CORS 问题。

According to the docs you have to use the applyMiddleware function to wire up the apollo server with express.根据文档,您必须使用 applyMiddleware function 将 apollo 服务器与 express 连接起来。

I am currently doing the following:我目前正在执行以下操作:

const app = express();

// CORS configuration

const corsOptions = {
    origin: 'http://localhost:3000',
    credentials: true
}

app.use(cors(corsOptions))

// Setup JWT authentication middleware

app.use(async (req, res, next) => {
    const token = req.headers['authorization'];
    if(token !== "null"){
        try {
            const currentUser = await jwt.verify(token, process.env.SECRET)
            req.currentUser = currentUser
        } catch(e) {
            console.error(e);
        }
    }
    next();
});

const server = new ApolloServer({ 
    typeDefs, 
    resolvers, 
    context: ({ req }) => ({ Property, User, currentUser: req.currentUser })
});

server.applyMiddleware({ app });


const PORT = process.env.PORT || 4000;

app.listen(PORT, () => {
    console.log(`Server listening on ${PORT}`);
})

For some reason my express middleware doesn't seem to be executing, when I try to do a request from localhost:3000 (client app) I get the typical CORS error由于某种原因,我的快速中间件似乎没有执行,当我尝试从 localhost:3000 (客户端应用程序)发出请求时,我得到典型的 CORS 错误

With apollo-server-express 1.3.6 I was doing the following without no issues:使用 apollo-server-express 1.3.6,我可以毫无问题地执行以下操作:

app.use(
    '/graphql',
    graphqlUploadExpress({ maxFileSize: 10000000, maxFiles: 10 }),
    bodyParser.json(),
    graphqlExpress(({ currentUser }) => ({
        schema,
        context: {
            // Pass Mongoose models
            Property,
            User,
            currentUser
        }
    }))
);

Now with the new version, event though the docs make this look like a straightforward migration, I don't seem to be able to make it work.现在有了新版本,尽管文档使这看起来像一个简单的迁移,但我似乎无法使其工作。 I've checked various articles and no one seems to be having the issue.我检查了各种文章,似乎没有人遇到问题。

From my understanding of the Apollo Server middleware API , CORS options, body-parser options and the graphql endpoint are treated as special entities that must be passed directly to the applyMiddleware param object.根据我对 Apollo Server 中间件 API 的理解,CORS 选项、body-parser 选项和 graphql 端点被视为必须直接传递给applyMiddleware参数对象的特殊实体。

So you want to try the following configuration:所以你想尝试以下配置:

const app = express();

// CORS configuration
const corsOptions = {
    origin: 'http://localhost:3000',
    credentials: true
}

// The following is not needed, CORS middleware will be applied
// using the Apollo Server's middleware API (see further below)
// app.use(cors(corsOptions))

// Setup JWT authentication middleware
app.use(async (req, res, next) => {
    const token = req.headers['authorization'];
    if(token !== "null"){
        try {
            const currentUser = await jwt.verify(token, process.env.SECRET)
            req.currentUser = currentUser
        } catch(e) {
            console.error(e);
        }
    }
    next();
});

const server = new ApolloServer({ 
    typeDefs, 
    resolvers, 
    context: ({ req }) => ({ Property, User, currentUser: req.currentUser })
});

// There is no need to explicitly define the 'path' option in
// the configuration object as '/graphql' is the default endpoint
// If you planned on using a different endpoint location,
// this is where you would define it.
server.applyMiddleware({ app, cors: corsOptions });

const PORT = process.env.PORT || 4000;

app.listen(PORT, () => {
    console.log(`Server listening on ${PORT}`);
})

With Apollo Server 2.x you supply the cors field in the constructor of ApolloServer .与阿波罗服务器2.X您提供cors在构造领域ApolloServer

So in your case, it should look like the following:所以在你的情况下,它应该如下所示:

const corsOptions = {
    origin: 'http://localhost:3000',
    credentials: true
}

// Setup JWT authentication middleware

app.use(async (req, res, next) => {
    const token = req.headers['authorization'];
    if(token !== "null"){
        try {
            const currentUser = await jwt.verify(token, process.env.SECRET)
            req.currentUser = currentUser
        } catch(e) {
            console.error(e);
        }
    }
    next();
});

const server = new ApolloServer({ 
    typeDefs, 
    cors: cors(corsOptions),
    resolvers, 
    context: ({ req }) => ({ Property, User, currentUser: req.currentUser })
});

server.applyMiddleware({ app });


const PORT = process.env.PORT || 4000;

app.listen(PORT, () => {
    console.log(`Server listening on ${PORT}`);
})

Here you find all params accepted by the apollo server: https://www.apollographql.com/docs/apollo-server/api/apollo-server.html#Parameters-2在这里您可以找到 apollo 服务器接受的所有参数: https : //www.apollographql.com/docs/apollo-server/api/apollo-server.html#Parameters-2

Here you find the relevant discussion: https://github.com/apollographql/apollo-server/issues/1142在这里你可以找到相关的讨论: https : //github.com/apollographql/apollo-server/issues/1142

The CORS settings come from ExpressJS, not from ApolloServer. CORS 设置来自 ExpressJS,而不是来自 ApolloServer。 If you want to add a custom or wildcard origin you have to handle it with a callback/handler function.如果要添加自定义或通配符来源,则必须使用回调/处理程序函数来处理它。

const server = new ApolloServer({
    ....,
    cors: {
        credentials: true,
        origin: (origin, callback) => {
            const whitelist = [
                "http://site1.com",
                "https://site2.com"
            ];

            if (whitelist.indexOf(origin) !== -1) {
                callback(null, true)
            } else {
                callback(new Error("Not allowed by CORS"))
            }
        }
    }
});

By default, the express middleware will instantiate cors middleware with default options on the graphql path, overriding any cors middleware configuration you yourself have specified for other paths(!)默认情况下,express 中间件将使用 graphql 路径上的默认选项实例化 cors 中间件,覆盖您自己为其他路径指定的任何 cors 中间件配置(!)

You can override the defaults when you apply the apollo middleware, eg您可以在应用 apollo 中间件时覆盖默认值,例如

apollo.applyMiddleware({ app, cors: {credentials: true, origin: true} })

I'm using apollo-server-express 2.17我正在使用 apollo-server-express 2.17

Just remove csrfPrevention: true and you are good to go只需删除 csrfPrevention: true 并且您对 go 很好

 import { ApolloServer } from 'apollo-server-express'; import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core'; import express from 'express'; import http from 'http'; async function startApolloServer(typeDefs, resolvers) { // Required logic for integrating with Express const app = express(); // Our httpServer handles incoming requests to our Express app. // Below, we tell Apollo Server to "drain" this httpServer, // enabling our servers to shut down gracefully. const httpServer = http.createServer(app); // Same ApolloServer initialization as before, plus the drain plugin // for our httpServer. const server = new ApolloServer({ typeDefs, resolvers, csrfPrevention: true, cache: 'bounded', plugins: [ApolloServerPluginDrainHttpServer({ httpServer })], }); // More required logic for integrating with Express await server.start(); server.applyMiddleware({ app, // By default, apollo-server hosts its GraphQL endpoint at the // server root. However, *other* Apollo Server packages host it at // /graphql. Optionally provide this to match apollo-server. path: '/', }); // Modified server startup await new Promise(resolve => httpServer.listen({ port: 4000 }, resolve)); console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`); }

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

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