【问题标题】:apollo-server-express CORS issueapollo-server-express CORS 问题
【发布时间】:2019-06-26 08:52:07
【问题描述】:

所以我正在迁移到 apollo-server-express 2.3.3(我使用的是 1.3.6) 我遵循了几个指南,进行了必要的调整,但陷入了 CORS 问题。

根据docs,您必须使用 applyMiddleware 函数将 apollo 服务器与 express 连接起来。

我目前正在做以下事情:

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}`);
})

由于某种原因,我的 express 中间件似乎没有执行,当我尝试从 localhost:3000(客户端应用程序)发出请求时,我收到典型的 CORS 错误

使用 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
        }
    }))
);

现在有了新版本,尽管文档使这看起来像一个简单的迁移,但我似乎无法让它工作。我查看了各种文章,似乎没有人遇到问题。

【问题讨论】:

    标签: node.js express graphql apollo-server


    【解决方案1】:

    根据我对 Apollo Server middleware API 的理解,CORS 选项、body-parser 选项和 graphql 端点被视为必须直接传递给 applyMiddleware 参数对象的特殊实体。

    所以你想试试下面的配置:

    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}`);
    })
    

    【讨论】:

    • 我认为这应该是公认的答案。这是唯一对我有用的答案。
    • 最新版apollo-server(2.4.8)在调用applyMiddleware方法时会报错:"To use Apollo Server with an existing express application, please use apollo-server-express"
    • @KarelFrajták 是的,applyMiddleware 方法由 apollo-server-{integration} 包提供,如 apollographql.com/docs/apollo-server/api/… 所述
    • @KarelFrajták 要清楚,我没有提到该软件包的必要性,因为 OP 表示他使用 apollo-server-express,它提供了方法
    • @Jaxx 我刚刚遇到了类似的问题,并且在各自的 GitHub 页面上也存在混淆
    【解决方案2】:

    使用 Apollo Server 2.x,您可以在 ApolloServer 的构造函数中提供 cors 字段。

    所以在你的情况下,它应该如下所示:

    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}`);
    })
    

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

    您可以在此处找到相关讨论: https://github.com/apollographql/apollo-server/issues/1142

    【讨论】:

      【解决方案3】:

      默认情况下,express 中间件将使用 graphql 路径上的默认选项实例化 cors 中间件,覆盖您自己为其他路径指定的任何 cors 中间件配置(!)

      您可以在应用 apollo 中间件时覆盖默认值,例如

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

      我正在使用 apollo-server-express 2.17

      【讨论】:

        【解决方案4】:

        CORS 设置来自 ExpressJS,而不是来自 ApolloServer。如果您想添加自定义或通配符来源,您必须使用回调/处理函数来处理它。

        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"))
                    }
                }
            }
        });
        

        【讨论】:

          猜你喜欢
          • 2019-11-27
          • 2021-02-05
          • 2020-08-08
          • 2020-05-05
          • 2020-09-03
          • 1970-01-01
          • 2023-03-08
          • 2018-06-17
          • 2021-02-20
          相关资源
          最近更新 更多