- 개발 중 브라우저 창끼리 데이터를 주고 받아야 하는 상황이 생겼다.
- 이를 구현하기 위해 방안을 찾아보던 결과, GPT가 제시한 방안이 PostMessage를 사용하는 것이었다.
- 사용법 및 용도에 대해 간단히 복습 겸 메모해보기로.
PostMessage란?
- Window 창 사이 Cross-Origin 통신을 할 수 있게 해주는 메서드다.
- 즉, 별도의 Cross Origin 설정을 하지 않더라도 안전하게 서로 다른 출처 간 통신이 가능하다!
개발 상황
PostMessage를 사용하여 구현하기로 한 상황은 대충 아래와 같았다. 아래의 상황을 재현하기 위해 간략하게 구현해보기로 한다.
- 웹 A에서 특정 메뉴를 통해 웹 B를 새 윈도우로 띄운다.
- 이때 웹 A는 웹 B가 필요로 하는 데이터를 보내주어야 한다.
- 웹 B는 웹 A가 보내온 데이터를 받아 필요한 작업을 수행한다.
웹 A (데이터를 보내는 쪽)
웹 A는 웹 B를 새 창에서 열고, 필요한 데이터를 PostMessage를 통해 보내야 한다.
export const PageA = () => {
// 데이터를 전송하는 페이지
const onClickButton = () => {
const newWindow = window.open('/pageB', '_blank');
setInterval(
() => newWindow?.postMessage('sample data!', 'http://localhost:5173')
, 3000
);
};
return (
<div>
<h3>Page A</h3>
<button onClick={onClickButton}>Click to Open Page B</button>
</div>
);
};
- open 메서드를 사용해 웹 B를 새 창으로 열고, 새롭게 열린 창을 변수로 저장한다.
- postMessage를 사용하여 새롭게 열린 창에 데이터를 보낸다.
- setInterval을 사용하는 이유는, 딜레이를 주지 않으면 새롭게 열린 창에서 바로 보내진 데이터를 받지 못할 수도 있기 때문이다.
- 따라서 몇 초의 시간이 지난 이후 데이터를 보냄으로써 새 창이 데이터를 확실히 받을 수 있도록 한다.
- 위 코드에서 postMessage가 받는 인자는 아래와 같다.
- 첫 번째 인자 (message): 전달할 데이터를 받는다.
- 두 번째 인자(targetOrigin): PostMessage를 받을 출처를 지정한다. 즉, PostMessage를 받을 출처가 targetOrigin과 일치하지 않는다면 MessageEvent가 전송되지 않는다. 이 재현 코드에서는 Vite를 쓰고 있어서, Vite의 기본 포트 번호인 5173을 사용하는 로컬호스트로 설정되어있다.
웹 B (데이터를 받는 쪽)
반대로 웹 B는 PostMessage를 통해 보내진 데이터를 받아야 한다. PostMessage 데이터를 받기 위해서는 이벤트 리스너를 등록하고, 데이터를 받았을 때 처리할 로직을 등록해두면 된다.
import { useEffect, useState } from "react";
export const PageB = () => {
const [receivedMessage, setReceivedMessage] = useState<string>();
useEffect(() => {
const getPostMessage = (event: MessageEvent) => {
if (event.origin === 'http://localhost:5173') {
setReceivedMessage(event.data);
}
};
window.addEventListener('message', getPostMessage);
return () => {
window.removeEventListener('message', getPostMessage);
};
}, []);
return (
<div>
<h3>Page B</h3>
<p>
Received Data is: {receivedMessage}
</p>
</div>
);
};
- useEffect 내부에서 addEventListener를 통해 PostMessage를 처리할 로직을 등록한다.
- 들어오는 이벤트는 MessageEvent 타입이다. 여기서 사용된 속성들은 아래와 같다.
- origin 속성: 해당 메시지의 출처를 가리킨다. 위에서와 마찬가지로 로컬호스트로 지정되어있다.
- data 속성: 메시지를 통해 보내진 데이터가 들어있다.
- 이 때, PostMessage를 보낸 출처(Origin)를 확인하는 작업이 중요하다.
- 위에서 언급했듯 PostMessage는 Cross-origin 통신이 가능하므로, 모든 출처에서 오는 데이터를 받을 수 있는 상황이라면 악용될 가능성이 있다. 따라서 origin을 확인하고, 허용할 출처에 한해서만 데이터를 받아 처리함으로써 안전성을 챙겨야 한다.
- Origin을 확인했다면 데이터를 state에 저장하고, 화면상에 출력한다.
결과
위에서 구현했듯 A에서 B 창을 띄우고 3초 후 PostMessage로 받은 메시지를 state에 저장한 후 띄우는 것을 확인할 수 있다.
- Window 객체 사이에서 동작하기 때문에 다양한 상황에서 활용할 수 있을 것 같다.
- 여기서는 새 창으로 했지만, 이후 요 때의 경험에 기반해서 페이지 내에 다른 페이지를 iframe으로 임베딩 한 후 PostMessage 를 추가했을 때도 작동하는 것을 확인할 수 있었다.
'공부 > FE' 카테고리의 다른 글
웹소켓 연결을 해보자 (커스텀 웹소켓 훅 만들어보기) (0) | 2024.11.16 |
---|---|
Hydration이란? (0) | 2024.11.07 |
실시간으로 서버에서 데이터를 가져와보기 (feat. Polling/Websocket/SSE) (0) | 2024.11.03 |
[Vite] Vite 알아보기 (0) | 2024.07.14 |
[웹 기본 쌓기] 렌더링, 리플로우/리페인트 (1) | 2024.01.10 |