들어가며

최근 같은 유형의 이슈가 연달아 터졌다.

 

에러 케이스

 

부모 - 자식 관계에 있는 iframe 또는 팝업 창에서 부모창의 함수를 실행하는 경우 아래와 같은 동일한 현상이 발생하여 이슈 처리 방법에 대해 남겨본다.

부모창 함수 호출 시 발생하는 에러 화면

 

원인

부모창과 자식창의 Origin이 다르기 때문이다.

브라우저는 Same-Origin 정책을 취하므로, 스크립트가 다른 Origin으로 접근하지 못하도록 한다.

(부모창과 자식창의 프토토콜, 호스트네임, 포트 번호 동일해야 함)

 

해결 방법

Window.postMessage() 사용하기

해당 메소드는 Window 오브젝트 간 Cross-Origin 통신을 안전하게 할 수 있도록 한다.

즉, Same-Origin이 아니더라도 통신할 수 있게 한다.

 

대체로 한 window는 다른 윈도우를 참조할 수 있고, (ex. targetWindow = window.opener), targetWindow.postMessage()를 통해 다른 window에 MessageEvent를 전송할 수 있다.

 

이를 통해 이벤트를 받는 window에서 사용할 수 있다.

 

부모창에서 자식창으로 메시지 전송시

targetWindow.postMessage(message, targetOrigin, [transfer]);

// 예시
window.opener.postMessage({data: 'data_to_send'}, 'https://child.abc.net');

 

message : 다른 window에 보낼 데이터

targetOrigin : targetWindow의 origin 지정. "*" 또는 URI이어야 함.

 

자식창에서 메시지 받을 때

window.addEventListener("message", receiveMessage);

function receiveMessage(event) {
  if (event.origin !== "https://parent.abc.net") return;
  
  // 자식창이 전송한 데이터 확인
  console.log(event.data);
  
  // TODO...
  
}

 

부모창의 함수를 호출하고 싶다면?

부모창에서 자식창으로 메시지 전송시

window.parent.postMessage(
  {
    funcName: 'openStudyPlanSurveyResult',
    params: ['1', '2', '3']
  },
  '*'
);

 

자식창에서 메소드 호출 방법

회사에서 필요한 jQuery, 구식으로 짠다면

$(window).on('message', function({ originalEvent : e }) {
	if (e.origin !== "https://parent.abc.net") return;

	var data = e.data;
    
	if (!$.isEmptyObject(data) && typeof(window[data.funcName]) === 'function') {
		var execFunc = new Function('return ' + data.funcName)();
		var param1 = data.params[0];
		var param2 = data.params[1];
		var param3 = data.params[2];
		// 함수 실행
		execFunc(param1, param2, param3);
	}
});

function openStudyPlanSurveyResult(a, b, c) {
	console.log('call', a, b, c);
}

 

조금 더 모던하게 짠다면

window.addEventListener('message', (e) => {
	if (e.origin !== "https://parent.abc.net") return;
    
	if (e.data.funcName) {
		// 함수 실행
		window[e.data.funcName](
			...e.data.params
		);
	}
});

function openStudyPlanSurveyResult(a, b, c) {
	console.log('call', a, b, c);
}

 


출처

https://developer.mozilla.org/ko/docs/Web/API/Window/postMessage

 

Window.postMessage() - Web API | MDN

window.postMessage() 메소드는 Window 오브젝트 사이에서 안전하게 cross-origin 통신을 할 수 있게 합니다. 예시로, 페이지와 생성된 팝업 간의 통신이나, 페이지와 페이지 안의 iframe 간의 통신에 사용할

developer.mozilla.org

https://velog.io/@jkas2020/CORS-iframe-%EB%B6%80%EB%AA%A8-%EC%9E%90%EC%8B%9D-%EA%B0%84-%ED%95%A8%EC%88%98%ED%98%B8%EC%B6%9C

 

[CORS] iframe 부모-자식 간 함수호출

며칠 전에 있었던 \[Vue.js] 외부 자바스크립트에서 Vue Component method 호출하기 이슈를 해결한 뒤 이어서 작업하던 중, 이번엔 상호 함수호출 중 CORS 이슈가 터졌다.포털을 구성하는 Vue.js 파일이 업

velog.io

https://stackoverflow.com/questions/25098021/securityerror-blocked-a-frame-with-origin-from-accessing-a-cross-origin-frame

 

SecurityError: Blocked a frame with origin from accessing a cross-origin frame

I am loading an <iframe> in my HTML page and trying to access the elements within it using JavaScript, but when I try to execute my code, I get the following error: SecurityError: Blocked a ...

stackoverflow.com

https://junspapa-itdev.tistory.com/55

 

서로 다른 도메인을 사용하는 부모창과 자식창(iframe) 간 데이크 통신하는 방법(크로스도메인, pos

부모창에서 iframe을 이용해서 부모창과 다른 도메인을 가진 자식창을 호출해야 하는 경우가 있습니다. 예를 들면, 내가 만든 홈페이지에 구글 애드센스나, 애드픽 등을 넣는 경우 등이 해당됩니

junspapa-itdev.tistory.com

 

'프론트엔드 > JavaScript' 카테고리의 다른 글

Scope  (0) 2020.12.26

글로벌 스코프

스크립트 전체에서 변수가 유효하다.

로컬 스코프

정의된 함수 안에서만 변수가 유효하다.
var로 선언된 변수는 로컬 스코프에 해당한다.

if (true) {
  var name = 'Park';
}
console.log(name);    // Park

var로 선언된 변수는 블록 스코프가 아니므로 블록을 빠져나온 후에도 변수가 유효하여 게속 사용할 수 있다.

var a = 0;

(function() {
  a++;
  console.log(a);    // 1
})();

console.log(a);        // 1

(function() {
  var b = 0;
  console.log(b);    // 0
})();

b++;
console.log(b);        // Error

a는 전역에 선언되었으므로 스크립트 전체에서 유효하지만 b는 익명 함수 내에서만 유효하므로 전역에서 호출된 콘솔문은 유효하지 않다.

글로벌 변수와 로컬 변수

var scope = 'A';

function getValue() {
  var scope = 'B';
  return scope;
}

console.log(getValue());    // B
console.log(scope);            // A
scope = 'A';

function getValue() {
  scope = 'B';
  return scope;
}

console.log(getValue());    // B
console.log(scope);            // B

위 두 예제를 통해서 var 를 사용하지 않고 선언된 변수는 모두 글로벌 변수로 간주되는 것을 알 수 있다.
로컬 변수를 정의하려면 반드시 var로 선언해야 한다.

로컬 변수의 유효 범위

var scope = 'A';

function getValue() {
  console.log(scope);        // 'undefined'
  var scope = 'B';
  return scope;
}

console.log(getValue());    // B
console.log(scope);            // A

함수 getValue가 초기 호출될 때 콘솔문에서 변수 scope는 유효하다.
이는 호이스팅에 의해 변수 scope의 선언문만 함수의 선두에 위치하도록 되어있기 때문이다.
즉 함수 getValue는 다음과 같게 된다.

function getValue() {
  var scope;
  console.log(scope);        // 'undefined'
  scope = 'B';
  return scope;
}

이러한 동작은 프로그램 버그의 원인이 되기도 하므로 로컬 변수는 함수의 선두에 직접 선언하도록 하자.

블록 스코프

블록 안에서만 변수가 유효하다.
let, const로 선언된 변수는 블록 스코프에 해당한다.

if (true) {
  let name = 'Park';
}
console.log(name);    // Error

let, const로 선언된 변수는 해당 블록에서만 유효하므로 블록을 빠져나오면 유효하지 않다.

let score = 90;

em

em은 부모 요소의 폰트 사이즈에 대한 상대적인 크기를 나타낸다.
만약 부모 요소의 폰트 사이즈가 10px일 때, 1em = 10px, 2em = 20px를 나타낸다.

rem

부모 엘리먼트가 아닌, 최상위 루트 html 요소에 대한 상대적인 크기를 나타낸다.

vw

viewport width에 대한 상대적인 크기를 나타낸다.
viewport는 현재 브라우저에 보이는 화면 전체를 나타낸다.
100vw는 viewport width의 가로 사이즈를 전부 다 차지한다. (100%)
50vw는 viewport width의 가로 사이즈의 절반만큼만 차지한다. (50%)

vh

viewport height에 대한 상대적인 크기를 나타낸다.

vmin

viewport width 또는 height 중 작은 값에 대한 상대적인 크기를 나타낸다.

vmax

viewport width 또는 height 중 큰 값에 대한 상대적인 크기를 나타낸다.

'프론트엔드 > CSS' 카테고리의 다른 글

기본 선택자와 복합 선택자  (0) 2020.12.19

기본 선택자 (Basic Selectors)

1. 전체 선택자 (Universal Selector)

*
모든 요소를 선택한다.

 

2. 태그 선택자 (Type Selector)

E
태그 이름이 E인 요소를 선택한다.

예제

li {
    color: red; 
}
<div>
  <ul>
    <li>마우스</li> <!-- Selected -->
    <li>키보드</li> <!-- Selected -->
  </ul>
  <span>사과</span>
</div>

3. 클래스 선택자 (Class Selector)

.E
HTML class 속성 값이 E인 요소를 선택한다.

4. 아이디 선택자 (ID Selector)

#E
HTML id 속성 값이 E인 요소를 선택한다.


복합 선택자 (Combinators)

1. 일치 선택자 (Basic Combinator)

EF
E와 F를 동시에 만족하는 요소를 선택한다.

예제

span.orange {
    color: red;
}
<div>
  <ul>
    <li>사과</li>
    <li>딸기</li>
    <li class="orange">오렌지</li>
  </ul>
  <div>당근</div>
  <p>토마토</p>
  <span class="orange">오렌지</span> <!-- Selected -->
</div>

2. 자식 선택자 (Child Combinator)

E > F
E의 자식 요소 F를 선택한다.

3. 후손(하위) 선택자 (Descendent Combinator)

E F
E의 후손(하위) 요소 F를 선택한다.
띄어쓰기가 선택자의 기호로 사용된다.

4. 인접 형제 선택자 (Adjacent Sibling Combinator)

E + F
E의 다음 형제 요소 F 하나만 선택한다.

예제

.orange + li {
    color: red; 
}
<ul>
  <li>딸기</li>
  <li>수박</li>
  <li class="orange">오렌지</li>
  <li>망고</li> <!-- Selected -->
  <li>사과</li>
</ul>

5. 일반 형제 선택자 (General Sibling Combinator)

E ~ F
E의 다음 형제 요소 F를 모두 선택한다.

예제

.orange ~ li {
      color: red;
}
<ul>
  <li>딸기</li>
  <li>수박</li>
  <li class="orange">오렌지</li>
  <li>망고</li> <!-- Selected -->
  <li>사과</li> <!-- Selected -->
</ul>

'프론트엔드 > CSS' 카테고리의 다른 글

단위 : em, rem, vw, vh, vmin, vmax  (0) 2020.12.20

+ Recent posts