jch*_*che 1 response-headers graphql express-graphql graphql-mutation
我正在实施 graphql 登录突变来验证用户登录凭据。Mutation 使用 bcrypt 验证密码,然后将 cookie 发送到客户端,客户端将根据 cookie 是买家还是所有者用户来呈现用户配置文件。
GraphQL 登录突变代码:
const Mutation = new GraphQLObjectType({
name: 'Mutation',
fields: {
loginUser: {
type: UserType,
args: {
email: { type: GraphQLString },
password: { type: GraphQLString }
},
resolve: function (parent, args, { req, res }) {
User.findOne({ email: args.email }, (err, user) => {
if (user) {
bcrypt.compare(args.password, user.password).then(isMatch => {
if (isMatch) {
if (!user.owner) {
res.cookie('cookie', "buyer", { maxAge: 900000, httpOnly: false, path: '/' });
} else {
res.cookie('cookie', "owner", { maxAge: 900000, httpOnly: false, path: '/' });
}
return res.status(200).json('Successful login');
} else {
console.log('Incorrect password');
}
});
}
});
}
}
}
});
Run Code Online (Sandbox Code Playgroud)
服务器.js:
app.use("/graphql",
(req, res) => {
return graphqlHTTP({
schema,
graphiql: true,
context: { req, res },
})(req, res);
});
Run Code Online (Sandbox Code Playgroud)
错误信息:
(node:10630) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
[0] at ServerResponse.setHeader (_http_outgoing.js:470:11)
[0] at ServerResponse.header (/Users/xxx/xxx/server/node_modules/express/lib/response.js:771:10)
[0] at ServerResponse.append (/Users/xxx/xxx/server/node_modules/express/lib/response.js:732:15)
[0] at ServerResponse.res.cookie (/Users/xxx/xxx/server/node_modules/express/lib/response.js:857:8)
[0] at bcrypt.compare.then.isMatch (/Users/xxx/xxx/server/schema/schema.js:89:41)
Run Code Online (Sandbox Code Playgroud)
我已经对此错误进行了一些研究,但似乎找不到相关的答案。问题似乎在于响应正文多次执行,因此“在将标头发送到客户端后无法设置标头”。由于我同时发送 res.cookie() 和 res.status(200),我该如何解决这个问题?
express-graphql已经设置状态并为您发送响应——无需在解析器内调用res.status或。res.json
GraphQL 始终返回状态 200,除非请求的查询无效,在这种情况下,它返回状态 400。如果在执行请求时发生错误,它们将包含在响应中(与errors返回的数组分开data),但status 仍为 200。这都是设计使然 - 请参阅此处的附加讨论。
您的解析器res.json应该返回适当类型的值(在本例中为UserType),或者返回一个将解析为该值的 Promise,而不是调用 。
此外,您不应该在解析器内部使用回调,因为它们与 Promise 不兼容。如果您使用的 bcrypt 库支持使用 Promises,请使用适当的 API。如果没有,请切换到有此功能的库(例如bcryptjs)或将回调包装在 Promise 中。无论您使用什么 ORM,都是如此。
最后,你的解析器应该看起来像这样:
resolve: function (parent, args, { req, res }) {
const user = await User.findOne({ email: args.email })
if (user) {
const isMatch = await bcrypt.compare(args.password, user.password)
if (isMatch) {
const cookieValue = user.owner ? 'owner' : 'buyer'
res.cookie('cookie', cookieValue, { maxAge: 900000, httpOnly: false, path: '/' })
return user
}
}
// If you want an error returned in the response, just throw it
throw new Error('Invalid credentials')
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2421 次 |
| 最近记录: |