将标头从 Apollo Vue 发送到 Node
Posted
技术标签:
【中文标题】将标头从 Apollo Vue 发送到 Node【英文标题】:Send headers from Apollo Vue to Node 【发布时间】:2021-11-01 00:30:18 【问题描述】:我正在使用 jwt、apollo-vue 和 graphql 使用 register 和 auth 做一个小 api
我无法通过查询(或通过突变设置)从/到我的后端获取数据。 但我可以从 Postman 那里完成,因为我知道如何在标头中发送令牌。
我也尝试在 vuex 的操作登录下方调用 onLogin(apolloClient, token)
。什么都没用
我是后端新手,如有任何建议,我将不胜感激
另一个问题?:如果在下面的函数中...
const authLink = setContext(async (_, headers ) =>
// add here console.log(localStorage.getItem('apollo-token'))
const token = await localStorage.getItem('apollo-token')
// and then console.log(token)
return ...
)
第一个控制台打印一个令牌,但第二个控制台打印null
。这对我来说很奇怪。
这是我的vue-apollo.js
import Vue from 'vue'
import VueApollo from 'vue-apollo'
import createApolloClient, restartWebsockets from 'vue-cli-plugin-apollo/graphql-client'
import setContext from 'apollo-link-context'
Vue.use(VueApollo)
const AUTH_TOKEN = 'apollo-token'
// Http endpoint
const httpEndpoint = process.env.VUE_APP_GRAPHQL_HTTP || 'http://localhost:3000/graphql'
const authLink = setContext(async (_, headers ) =>
const token = await localStorage.getItem(AUTH_TOKEN)
return
...headers,
Authorization: token || ''
)
// Files URL root
export const filesRoot = process.env.VUE_APP_FILES_ROOT || httpEndpoint.substr(0, httpEndpoint.indexOf('/graphql'))
Vue.prototype.$filesRoot = filesRoot
// Config
const defaultOptions =
httpEndpoint,
wsEndpoint: null,
tokenName: AUTH_TOKEN,
websocketsOnly: false,
s-s-r: false,
link: authLink
export const apolloClient = createApolloClient(
...defaultOptions,
)
export function createProvider(options = )
const apolloClient, wsClient = createApolloClient(
...defaultOptions,
...options,
)
apolloClient.wsClient = wsClient
const apolloProvider = new VueApollo(
defaultClient: apolloClient,
defaultOptions:
$query:
// fetchPolicy: 'cache-and-network',
,
,
errorHandler(error)
// eslint-disable-next-line no-console
console.log('%cError', 'background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;', error.message)
,
)
return apolloProvider, apolloClient
// Manually call this when user log in
export async function onLogin(apolloClient, token)
if (typeof localStorage !== 'undefined' && token)
localStorage.setItem(AUTH_TOKEN, token)
if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
try
await apolloClient.resetStore()
catch (e)
// eslint-disable-next-line no-console
console.log('%cError on cache reset (login)', 'color: orange;', e.message)
// Manually call this when user log out
export async function onLogout(apolloClient)
if (typeof localStorage !== 'undefined')
localStorage.removeItem(AUTH_TOKEN)
if (apolloClient.wsClient) restartWebsockets(apolloClient.wsClient)
try
await apolloClient.resetStore()
catch (e)
// eslint-disable-next-line no-console
console.log('%cError on cache reset (logout)', 'color: orange;', e.message)
来自 vue 的 main.js
// HTTP connection to the API
const httpLink = createHttpLink(
// You should use an absolute URL here
uri: 'http://localhost:3000/graphql',
)
// Cache implementation
const cache = new InMemoryCache()
// Create the apollo client
const apolloClient = new ApolloClient(
link: httpLink,
cache,
)
Vue.config.productionTip = false
Vue.use(VueScreen)
.use(VueApollo)
const apolloProvider = new VueApollo(
defaultClient: apolloClient,
)
new Vue(
router,
store,
vuetify,
apolloProvider,
render: h => h(App)
).$mount('#app')
编辑:更多代码
这是查询,在 vue 上的视图
import gql from "graphql-tag";
export default
name: "Home",
apollo:
Users: gql`
Users
_id
username
email
password
token
createdAt
,
`,
,
;
我收到的错误是:
bundle.esm.js:75 POST http://localhost:3000/graphql 500(内部服务器错误)
发送查询“用户”服务器错误:响应不成功:收到状态代码 500 在 throwServerError 处
在后台,这是我的查询
Query:
async Users(_, req, context)
const auth = checkAuth(context)
if (auth.id)
const users = await User.find()
users.forEach(e =>
e.password = null
)
return users
else
return new Error("must be logged.")
,
这是我的 checkAuth.js
import jwt from 'jsonwebtoken'
import AuthenticationError from 'apollo-server'
import 'dotenv/config'
module.exports = (context) =>
const authHeader = context.headers.authorization;
console.log("headers: ",context.headers)
if (authHeader)
const token = authHeader.split('Bearer ')[1];
if (token)
try
const user = jwt.verify(token, process.env.SECRET_KEY);
return user
catch (err)
return new AuthenticationError("Invalid token.")
return new Error("Token must be 'Bearer [token]'")
return new Error("I need a token bro!")
编辑 2
后端收到的 context.header
headers:
host: 'localhost:3000',
connection: 'keep-alive',
'content-length': '160',
'sec-ch-ua': '"Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"',
accept: '*/*',
'sec-ch-ua-mobile': '?0',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
'content-type': 'application/json',
origin: 'http://localhost:8081',
'sec-fetch-site': 'same-site',
'sec-fetch-mode': 'cors',
'sec-fetch-dest': 'empty',
referer: 'http://localhost:8081/',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'es-419,es;q=0.9,en;q=0.8'
,
【问题讨论】:
当你“说什么都没用”时,你能说得更清楚吗?如果你看看控制台。执行查询时会打印什么错误? 是的,很抱歉。该错误仅发生在前端。 Postman 中的相同查询,但在标头中有标记,工作正常。错误和更多代码现在添加到问题下方。 @Joyescat 也许有某种方法可以从前端的查询中发送 Apollo 对象中的标头? 后端日志打印什么错误?是“无效令牌。”、“令牌必须是 'Bearer [token]'”或“我需要令牌兄弟!”触发错误? “有某种方法可以从前端的查询中发送 Apollo 对象中的标头?”是什么意思?您已经在vue-apollo.js
中的setContext
函数中发送带有令牌的标头
【参考方案1】:
据我所知,您只在授权标头中发送令牌。
const authLink = setContext(async (_, headers ) =>
const token = await localStorage.getItem(AUTH_TOKEN)
return
...headers,
Authorization: token || ''
)
但您希望在后端找到不记名令牌:
module.exports = (context) =>
const authHeader = context.headers.authorization;
console.log("headers: ",context.headers)
if (authHeader)
const token = authHeader.split('Bearer ')[1]; << Your code is breaking here
if (token)
try
const user = jwt.verify(token, process.env.SECRET_KEY);
return user
catch (err)
return new AuthenticationError("Invalid token.")
return new Error("Token must be 'Bearer [token]'")
return new Error("I need a token bro!")
您必须发送 'Bearer [token]' 而不仅仅是令牌。像这样:
const authLink = setContext(async (_, headers ) =>
const token = await localStorage.getItem(AUTH_TOKEN)
return
...headers,
Authorization: `Bearer $token`
)
【讨论】:
【参考方案2】:在documentation 中,setContext
是这样使用的:
const setAuthorizationLink = setContext((request, previousContext) => (
headers: authorization: "1234"
));
setContext 函数采用返回对象的函数或返回对象的 Promise 来设置请求的新上下文。
在下面的代码中,您只返回标题。当你应该返回上下文时。
const authLink = setContext(async (_, headers ) =>
const token = await localStorage.getItem(AUTH_TOKEN)
return
...headers,
Authorization: token || ''
)
试试这个
const authLink = setContext(async (_, headers ) =>
const token = await localStorage.getItem(AUTH_TOKEN)
return
headers:
...headers,
Authorization: token || ''
)
【讨论】:
它也没有用。我在 checkAuth.js 中收到的 context.header 没有授权密钥。【参考方案3】:vue-apollo.js
文件未使用。
在您的main.js
中,您在Vue 中注入的apolloClient
在main.js
中声明,并且不包含authLink
。 你在vue-apollo.js
中的所有代码没有被调用。
所以不要这样:
// HTTP connection to the API
const httpLink = createHttpLink(
// You should use an absolute URL here
uri: 'http://localhost:3000/graphql',
)
// Cache implementation
const cache = new InMemoryCache()
// Create the apollo client
const apolloClient = new ApolloClient(
link: httpLink,
cache,
)
Vue.config.productionTip = false
Vue.use(VueScreen)
.use(VueApollo)
const apolloProvider = new VueApollo(
defaultClient: apolloClient,
)
new Vue(
router,
store,
vuetify,
apolloProvider,
render: h => h(App)
).$mount('#app')
试试这个:
import createProvider from 'vue-apollo.js';
Vue.config.productionTip = false
Vue.use(VueScreen)
.use(VueApollo)
const apolloProvider, apolloClient = createProvider();
new Vue(
router,
store,
vuetify,
apolloProvider,
render: h => h(App)
).$mount('#app')
【讨论】:
天哪,非常感谢。你拯救了我的一天,梅西祝福你以上是关于将标头从 Apollo Vue 发送到 Node的主要内容,如果未能解决你的问题,请参考以下文章
如何将 cookie 添加到 vue-apollo 请求中?
Post Request express:发送到客户端后无法设置标头