如何将 cookie 添加到 vue-apollo 请求中?

Posted

技术标签:

【中文标题】如何将 cookie 添加到 vue-apollo 请求中?【英文标题】:How to add cookies to vue-apollo request? 【发布时间】:2020-02-22 06:11:05 【问题描述】:

我使用vue-cli-plugin-apollo,我想通过cookie将用户选择的language从前端发送到后端。

作为vue-apollo.js,我使用下一个模板

import Vue from 'vue'
import VueApollo from 'vue-apollo'
import  createApolloClient, restartWebsockets  from 'vue-cli-plugin-apollo/graphql-client'

// Install the vue plugin
Vue.use(VueApollo)

// Name of the localStorage item
const AUTH_TOKEN = 'apollo-token'

// Http endpoint
const httpEndpoint = process.env.VUE_APP_GRAPHQL_HTTP || 'http://localhost:4000/graphql'

// 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 = 
  // You can use `https` for secure connection (recommended in production)
  httpEndpoint,
  // You can use `wss` for secure connection (recommended in production)
  // Use `null` to disable subscriptions
  wsEndpoint: process.env.VUE_APP_GRAPHQL_WS || 'ws://localhost:4000/graphql',
  // LocalStorage token
  tokenName: AUTH_TOKEN,
  // Enable Automatic Query persisting with Apollo Engine
  persisting: false,
  // Use websockets for everything (no HTTP)
  // You need to pass a `wsEndpoint` for this to work
  websocketsOnly: false,
  // Is being rendered on the server?
  s-s-r: false,

  // Override default apollo link
  // note: don't override httpLink here, specify httpLink options in the
  // httpLinkOptions property of defaultOptions.
  // link: myLink

  // Override default cache
  // cache: myCache

  // Override the way the Authorization header is set
  // getAuth: (tokenName) => ...

  // Additional ApolloClient options
  // apollo:  ... 

  // Client local data (see apollo-link-state)
  // clientState:  resolvers:  ... , defaults:  ...  


// Call this in the Vue app file
export function createProvider (options = ) 
  // Create apollo client
  const  apolloClient, wsClient  = createApolloClient(
    ...defaultOptions,
    ...options,
  )
  apolloClient.wsClient = wsClient

  // Create vue apollo provider
  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

取自here。显示所有选项here。

我在不同的 github 讨论中看到 cookies 必须放在 headers 中,例如 here。然后我发现apollo-link-http 有headers 选项,所以最后我尝试了不同的变体...:

httpLinkOptions: 
  headers: 

    // Tried something like:
    cookie[s]: 'language=en; path=/;'

    // and something like:
    cookie[s]: 
      language: 'en'
    
  

但没有运气。

如果是 cookieS,我会收到 Error: Network error: Failed to fetch

如果是cookie,发送请求没有问题,但后端看不到language cookie。

我使用Postman 仔细检查了后端,在这种情况下,后端接收到手动添加language cookie 的请求。

谁能帮帮我?

【问题讨论】:

【参考方案1】:

找到解决方案。

前端设置

    创建 cookie:
export function languageCookieSet (lang) 
  document.cookie = `language=$lang; path=/;`

    httpLinkOptions 添加到defaultOptionsvue-apollo.js
const defaultOptions = 
  ...

  httpLinkOptions: 
    credentials: 'include'
  ,

  ...

后端设置

作为后端,我使用Django(当前为 v2.2.7)。

    对于开发,我们需要使用django-cors-headers 我的development.py 现在看起来像:
from .production import *

CORS_ORIGIN_WHITELIST = (
    'http://localhost:8080',
)
CORS_ALLOW_CREDENTIALS = True

INSTALLED_APPS += ['corsheaders']

MIDDLEWARE.insert(0, 'corsheaders.middleware.CorsMiddleware')
    添加到production.py:
LANGUAGE_COOKIE_NAME = 'language'

LANGUAGE_COOKIE_NAME的默认值是django_language,所以如果适合你就改

document.cookie = `language=$lang; path=/;`

document.cookie = `django_language=$lang; path=/;`
    现在我们可以在后端获取前端语言:
import graphene

from django.contrib.auth import get_user_model
from django.utils.translation import gettext as _

from .views import user_activation__create_email_confirmation

User = get_user_model()

class UserRegister(graphene.Mutation):
    """
    mutation 
      userRegister(email: "test@domain.com", password: "TestPass") 
        msg
      
    
    """

    msg = graphene.String()

    class Arguments:
        email = graphene.String(required=True)
        password = graphene.String(required=True)

    def mutate(self, info, email, password):
        request = info.context

        # Here we get either language from our cookie or from
        # header's "Accept-Language" added by Browser (taken
        # from its settings)
        lang = request.LANGUAGE_CODE
        print('lang:', lang)

        if User.objects.filter(email=email).exists():
            # In our case Django translates this string based
            # on the cookie's value (the same as "request.LANGUAGE_CODE")
            # Details: https://docs.djangoproject.com/en/2.2/topics/i18n/translation/
            msg = _('Email is already taken')
        else:
            msg = _('Activation link has been sent to your email.')

            user = User(email=email)
            user.set_password(password)
            user.save()
            user_activation__create_email_confirmation(info.context, user)

        return UserRegister(msg=msg)

注意:我尚未在生产环境中测试这些更改,但在生产环境中,我只使用一台服务器,其中前端和后端位于 nginx 后面,这就是 CORS 设置位于 @ 的原因987654338@ 而不是 production.py。同样在生产中credentials: 'include' 可能会更改为credentials: 'same-origin'(即更严格)。

【讨论】:

以上是关于如何将 cookie 添加到 vue-apollo 请求中?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Vuepress 站点中使用 vue-apollo?

如何从 vue-apollo 中访问 this.$route?

当我在 Vue-apollo 中使用本地状态时如何获取远程 GraphQL 数据

如何将 cookie 添加到拖放 div

如何通过 Django Channels 将 cookie 添加到标头?

将cookie添加到chromedriver时如何修复Selenium中的“无效参数:无效'到期'”?