我挑战的背景
我正在建立一个无头的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。
代码
当我尝试从操作创建者向购物车中添加东西时(我正在使用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);
}
});
答案 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