javascript - 部署到 Heroku 后节点/apollo/express 服务器的 Cookie 问题
问题描述
我正在使用 apollo 构建节点 js 服务器,并使用 next.js/apollo 客户端构建前端。我的问题是,在 localhost 上一切正常,但在部署到 Heroku 后未设置 cookie。我正在从服务器获取数据并将我重定向到主页,但在页面重新加载后它再次将我重定向到登录页面。
这是阿波罗服务器代码
import cors from 'cors'
import Redis from 'ioredis'
import dotenv from 'dotenv'
import express from 'express'
import mongoose from 'mongoose'
import session from 'express-session'
import connectRedis from 'connect-redis'
import { ApolloServer } from 'apollo-server-express'
import typeDefs from './schema'
import resolvers from './resolvers'
dotenv.config({
path: `.env.${process.env.NODE_ENV}`,
})
const port = process.env.PORT || 4000
const dev = process.env.NODE_ENV !== 'production'
const RedisStore = connectRedis(session)
const startServer = async () => {
await mongoose
.connect(process.env.DB_URL, { useNewUrlParser: true })
.then(() => console.log(` MongoDB Connected...`))
.catch(err => console.log(`❌ MongoDB Connection error: ${err}`))
const app = express()
const server = new ApolloServer({
typeDefs,
resolvers,
playground: !dev
? false
: {
settings: {
'request.credentials': 'include',
},
},
context: ({ req, res }) => ({ req, res }),
})
app.disable('x-powered-by')
app.set('trust proxy', 1)
app.use(
cors({
credentials: true,
origin:
process.env.NODE_ENV === 'production'
? process.env.FRONT_END_URL
: 'http://localhost:3000',
}),
)
app.use((req, _, next) => {
const authorization = req.headers.authorization
if (authorization) {
try {
const cid = authorization.split(' ')[1]
req.headers.cookie = `cid=${cid}`
console.log(cid)
} catch (err) {
console.log(err)
}
}
return next()
})
app.use(
session({
store: new RedisStore({
host: process.env.REDIS_HOST,
port: process.env.REDIS_PORT,
pass: process.env.REDIS_PASS,
}),
name: process.env.SESS_NAME,
secret: process.env.SESS_SECRET,
saveUninitialized: false,
resave: false,
cookie: {
httpOnly: true,
maxAge: 1000 * 60 * 60 * 24 * 7, // 7 days
secure: false,
},
}),
)
server.applyMiddleware({ app, cors: false })
app.listen({ port }, () =>
console.log(
` Server ready at http://localhost:${port}${server.graphqlPath}`,
),
)
}
startServer()
这是解析器
import gravatar from 'gravatar'
import bcrypt from 'bcrypt'
import { User } from '../models'
import { isAuthenticated, signOut } from '../auth'
import { loginSchema, registerSchema } from '../utils'
export default {
Query: {
users: (parent, args, { req }, info) => {
isAuthenticated(req)
return User.find({})
},
user: (parent, { id }, context, info) => {
isAuthenticated(req)
return User.findById(id)
},
me: (parent, args, { req }, info) => {
isAuthenticated(req)
return User.findById(req.session.userId)
},
},
Mutation: {
signUp: async (parent, args, { req }, info) => {
// isAuthenticated(req)
args.email = args.email.toLowerCase()
try {
await registerSchema.validate(args, { abortEarly: false })
} catch (err) {
return err
}
args.avatar = await gravatar.url(
args.email,
{
protocol: 'https',
s: '200', // Size
r: 'pg', // Rating
d: 'mm', // Default
},
true,
)
args.password = await bcrypt.hash(args.password, 12)
const user = await User.create(args)
req.session.userId = user.id
return user
},
signIn: async (parent, args, { req }, info) => {
// isAuthenticated(req)
const { email, password } = args
try {
await loginSchema.validate(args, { abortEarly: false })
} catch (err) {
return err
}
const user = await User.findOne({ email })
if (!user || !(await bcrypt.compare(password, user.password))) {
throw new Error('Incorrect email or password. Please try again.')
}
req.session.userId = user.id
return user
},
signOut: (parent, args, { req, res }, info) => {
return signOut(req, res)
},
},
}
这是前端的 apollo 客户端(我正在使用 next.js 中的 with-apollo-auth 示例)
import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { createHttpLink } from 'apollo-link-http'
import { setContext } from 'apollo-link-context'
import fetch from 'isomorphic-unfetch'
let apolloClient = null
if (!process.browser) {
global.fetch = fetch
}
function create(initialState, { getToken }) {
const httpLink = createHttpLink({
uri:
process.env.NODE_ENV === 'development'
? 'http://localhost:4000/graphql'
: process.env.BACK_END_URL,
credentials: 'include',
})
const authLink = setContext((_, { headers }) => {
const token = getToken()
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : '',
},
}
})
return new ApolloClient({
connectToDevTools: process.browser,
ssrMode: !process.browser,
link: authLink.concat(httpLink),
cache: new InMemoryCache().restore(initialState || {}),
})
}
export default function initApollo(initialState, options) {
if (!process.browser) {
return create(initialState, options)
}
if (!apolloClient) {
apolloClient = create(initialState, options)
}
return apolloClient
}
提前致谢。
解决方案
推荐阅读
- graphql - 图表:没有为子图查询中的 ID 参数提供值
- html - 如何在 CSS 中使用 flex-shrink 换行?
- r - 带有密码输入的 TextInputIcon(来自 Shinywidgets)
- react-native - 使用 useRecoilValue 时 React Native Invalid hook call
- reactjs - firebase 显示大量无法解释的读取的原因可能是什么?
- python - 水平滚动元素 - Selenium Python
- vba - 循环循环 - Vba
- json - JSON data unloaded from Snowflake to S3 external stage
- java - 使用 apache camel cxf-rs 路由请求的正确方法是什么?
- javascript - 如何使用 jed 翻译 yoast?