programing

동일한 도메인 사이트 간 쿠키 공유 - 헤드리스/디커플링된 CMS

abcjava 2023. 3. 7. 20:57
반응형

동일한 도메인 사이트 간 쿠키 공유 - 헤드리스/디커플링된 CMS

나의 도전의 배경은

헤드리스 WordPress / WooCommerce Store를 만들고 있습니다.

헤드리스 CMS의 개념이 익숙하지 않은 경우 WordPress/WooCommerce REST API에서 스토어의 콘텐츠(제품 및 그 이미지, 텍스트)를 가져옵니다.이렇게 하면 클라이언트용 CMS 대시보드의 이점을 얻을 수 있습니다.또한 최신 언어/라이브러리에서 개발할 수 있습니다.리액션!

가능하다면 WordPress/WooCommerce/PHP에서 체크아웃을 유지하고 싶습니다.이 코드/보일러플레이트를 프로젝트에 따라서는 지불 게이트웨이를 잘라내고 변경해야 할 것 같습니다.또, PHP/WordPress에서는, 이 시큐어한 PCI 준거성을 실현하는 것이 훨씬 쉬워집니다.플러그인은 매우 많습니다.

이는 사용자가 주문을 완료하고 싶을 때 CMS 프론트엔드(WordPress, PHP)로 리디렉션되는 카트를 제외하고 전체 스토어/프런트엔드가 React에 상주함을 의미합니다.

과제

이로 인해 세션용 쿠키 관리는 다소 비타협적이고 비정통적입니다.사용자가 스토어(React 사이트)에서 체크아웃(WooCommerce/PHP 사이트)으로 리디렉션되면 두 사이트 간에 카트 세션을 유지해야 합니다.

또한 WooCommerce에 대한 요청은 내 React 클라이언트가 있는 노드/Express 서버를 통해 라우팅됩니다.WordPress 주소를 가리고 싶기 때문에, GraphQL을 적용하여 요청과 응답을 정리할 수 있습니다.이 문제는 클라이언트와 CMS가 중간자(노드 서버)를 통해 통신하기 때문에 쿠키가 손실된다는 것입니다.쿠키를 수동으로 관리하려면 추가 논리가 필요합니다.

솔루션 아키텍처의 대략적인 개요

코드

카트에 무언가를 추가하려고 할 때 작업 작성자(상태 관리에 Redx를 사용 중)에서 노드/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));
  }
};

그런 다음 노드/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);
    }
});

@TarunLalwani(고맙습니다!)가 코멘트에서 준 힌트로, 해결책을 생각해 냈습니다.

쿠키 도메인 설정

2개의 다른 사이트를 사용하고 있었기 때문에, 이 작업을 실시하기 위해서는, 양쪽이 같은 도메인에 있는 것과 모든 cookie에 도메인이 설정되어 있는 것을 확인할 필요가 있었습니다.이것에 의해, 노드/익스프레스 서버간의 요구에 쿠키가 포함되어 있는 것을 확인할 수 있었습니다(예: 설치 장소). somedomain.com CMS( WooCommerce CMS(WooCommerce CMS)에). wp.somedomain.com 「」, 「」의,wp.somedomain서브도메인이것은, 다음의 설정에 의해서 실현되었습니다.define( 'COOKIE_DOMAIN', 'somedomain.com' ); 집에서는wp-config.phpCMS cms cms ★

쿠키 수동 가져오기 및 설정

요구가 클라이언트를 통해 노드/익스프레스 서버를 통해 라우팅되는 동안 쿠키를 포함하기 위해 코드에는 상당한 추가 논리가 필요했습니다.

리액트에서는 쿠키가 존재하는지 확인하고 존재하는지 여부를 GET 요청 헤더로 Node/Express 서버로 전송해야 했습니다.

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.headerssession-dataCookieCMS로 .

쿠키를 수 없는 에서 첫 으로 가져와 (CMS).setCookieFunc

app.get('/api/addtocart', async (req, res) => {
  try {
    const productId = parseInt(req.query.productId);
    const quantity = parseInt(req.query.quantity);
    const sessionData = req.headers['session-data'];
    const headers = {};
    if (sessionData) headers.Cookie = sessionData;
    const response = await axios.post(`${WP_API}/wc/v2/cart/add`, {
      product_id: productId,
      quantity
    }, { headers });
    if (!sessionData) {
      const cookies = response.headers['set-cookie'];
      const setCookieFunc = (cookie) => {
        const [cookieKeyValue, ...cookieOptionsArr] = cookie.split('; ');
        const cookieKey = cookieKeyValue.split('=')[0];
        const cookieValue = decodeURIComponent(cookieKeyValue.split('=')[1]);
        const cookieOptions = { };
        cookieOptionsArr.forEach(option => (cookieOptions[option.split('=')[0]] = option.split('=')[1]));
        if (cookieOptions.expires) {
          const expires = new Date(cookieOptions.expires);
          cookieOptions.expires = expires;
        }
        res.cookie(cookieKey, cookieValue, cookieOptions);
      };
      cookies.map(cookie => setCookieFunc(cookie));
    }
    return res.json(response.data);
  } catch (error) {
    // Handle error
    return res.json(error);
  }
});

이것이 그 문제에 대한 가장 우아한 해결책인지는 모르겠지만, 나에게는 효과가 있었다.


메모들

리액트 클라이언트의 쿠키와 상호 작용하기 위해 js-cookie 라이브러리를 사용했습니다.


고차스

개발 환경(localhost 사용)에서 이 작업을 수행하려는 경우 몇 가지 추가 작업을 수행해야 합니다.명시적 도메인이 있는 로컬 호스트의 쿠키를 참조하십시오.

언급URL : https://stackoverflow.com/questions/51307403/sharing-cookies-between-sites-on-the-same-domain-headless-decoupled-cms

반응형