在同一域中的站点之间共享Cookie-无头/解耦CMS

时间:2018-07-12 13:49:06

标签: wordpress reactjs express cookies axios

我挑战的背景

我正在建立一个无头的WordPress / WooCommerce商店。

如果您不熟悉无头CMS的概念,我会通过WordPress / WooCommerce REST API拉出商店的内容(产品及其图像,文本)。这样,我可以为客户使用CMS仪表板,而我可以使用现代语言/库进行开发,例如我的React-

如果可能的话,我想将结帐保留在WordPress / WooCommerce / PHP中。根据项目的不同,我会将此代码/样板应用到我怀疑必须砍掉和更改支付网关的地方,并且使此安全且符合PCI的要求在PHP / WordPress中变得容易得多-为此,有很多插件。

这意味着整个商店/前端都将驻留在React中,但购物车除外,当用户希望完成订单时,该购物车会将用户重定向到CMS前端(WordPress,PHP)。 / p>

挑战

这使管理会话的cookie变得不直观且不合常规。当用户从商店(React站点)重定向到结帐(WooCommerce / PHP站点)时,购物车会话必须在两个站点之间持续。

另外,对WooCommerce的请求是通过我的React客户端所在的Node / Express服务器路由的。我这样做是因为我想让WordPress地址保持模糊,因此我可以应用GraphQL来清理我的请求和响应。 问题在于,在此过程中,由于我的客户端和CMS通过中间人(Node服务器)进行通信,因此丢失了cookie。我需要额外的逻辑来手动管理cookie。

Rough sketch of architecture of solution

代码

当我尝试从操作创建者向购物车中添加东西时(我正在使用Redux进行状态管理),我在Node / Express服务器上点击了api对应的端点:

export const addToCart = (productId, quantity) => async (dispatch) => {
  dispatch({type: ADD_TO_CART});
  try {
    // Manually append cookies somewhere here
    const payload = await axios.get(`${ROOT_API}/addtocart?productId=${productId}&quantity=${quantity}`, {
      withCredentials: true
    });
    dispatch(addToSuccess(payload));
  } catch (error) {
    dispatch(addToCartFailure(error));
  }
};

然后在Node / Express服务器上,我向WooCommerce提出请求:

app.get('/api/addtocart', async (req, res) => {
    try {
      // Manually retrieve & append cookies somewhere here
      const productId = parseInt(req.query.productId);
      const quantity = parseInt(req.query.quantity);
      const response = await axios.post(`${WP_API}/wc/v2/cart/add`, {
        product_id: productId,
        quantity
      });
      return res.json(response.data);
    } catch (error) {
      // Handle error
      return res.json(error);
    }
});

1 个答案:

答案 0 :(得分:1)

利用@TarunLalwani(感谢一百万!)在他的评论中提供的线索,我设法制定了解决方案。

Cookie域设置

自从我使用两个单独的站点以来,为了使其正常工作,我必须确保它们都在同一个域中,并且该域在所有cookie中都已设置。这样可以确保Cookie包含在我的请求中,位于节点/ Express服务器(例如位于somedomain.com和WooCommerce CMS之间(例如wp.somedomain.com)之间,而不是{{1 }}子域。这是通过在CMS上的wp.somedomain中设置define( 'COOKIE_DOMAIN', 'somedomain.com' );来实现的。

手动获取和设置Cookie

我的代码需要大量的附加逻辑,以便在通过客户端通过我的Node / Express服务器路由请求时包含cookie。

在React中,我必须检查cookie是否存在,如果存在,我必须通过GET请求的标头将其发送到Node / Express服务器。

wp-config.php

在Node / Express Server上,我必须检查是否包含一个cookie(保存在import Cookies from 'js-cookie'; export const getSessionData = () => { // WooCommerce session cookies are appended with a random hash. // Here I am tracking down the key of the session cookie. const cookies = Cookies.get(); if (cookies) { const cookieKeys = Object.keys(cookies); for (const key of cookieKeys) { if (key.includes('wp_woocommerce_session_')) { return `${key}=${Cookies.get(key)};`; } } } return false; }; export const addToCart = (productId, quantity) => async (dispatch) => { dispatch({type: ADD_TO_CART}); const sessionData = getSessionData(); const config = {}; if (sessionData) config['session-data'] = sessionData; console.log('config', config); try { const payload = await axios.get(`${ROOT_API}/addtocart?productId=${productId}&quantity=${quantity}`, { withCredentials: true, headers: config }); dispatch(addToSuccess(payload)); } catch (error) { dispatch(addToCartFailure(error)); } }; 中,其密钥为req.headers-在此处使用session-data作为密钥是非法的),然后将其添加到我的CMS的请求标头中。

如果找不到附加的cookie,则表示这是会话中的第一个请求,因此,我不得不从从CMS返回的响应中手动获取cookie,并将其保存到客户端({{ 1}})。

Cookie

我不确定这是否是解决问题的最优雅的方法,但是它对我有用。


注释

我使用js-cookie库与React客户端上的cookie进行交互。


陷阱

如果要在开发环境中(使用localhost)进行此工作,则需要完成一些额外的工作。参见Cookies on localhost with explicit domain