분류

레이블이 javascript인 게시물을 표시합니다. 모든 게시물 표시
레이블이 javascript인 게시물을 표시합니다. 모든 게시물 표시

2019년 1월 18일 금요일

Iframe 을 이용한 cross - domain 메시지 교환

하나의 세션에 대한 인증 결과와 경과 시간에 대한 주기적인 체크를 할 수 있는 방법이 필요했습니다.

여러 다른 url을 가진 사이트간의 통신은 cross-domain 보안 정책에 의해 기본적으로 차단되어 있는 상황에서 보안정책을 변경하는 것 보단 간단한 메시지를 전달하는 정도의 방식으로 프로그래밍을 하는 것이 수월하기에 iframe을 이용해 서로 다른 도메인간의 통신을 유도하는 방법을 찾아보았습니다.

일단 메시지를 보내는 주 사이트와, 메시지를 받는 사이트 측으로 분리해서 아래와 같은 스크립트를 만들어보았습니다.

크로스 도메인을 위한 스크립트 구성 

부모페이지에 추가된 script (메시지를 받는 쪽)
//iframe를 첨부할 jsp 내에 아래와 같은 스크립트와 iframe을 추가합니다. 

<script type="text/javascript">
//iframe에서 전송하는 메시지를 받을 리스너를 생성 
//(iframe과 동일한 페이지 현재 스크립트가 있어야함)
function receiveMessage(event){
//리스너 이벤트 전송자와, 명령어가 동일할 경우 수행 
if(event.data === "testMessage" && event.origin === "http://testsite"){ 
//event.data는 리스너를 통해 전달받는 데이터입니다. 
// ===은 데이터 타입과 데이터 내용이 모두 일치하는지 비교하는 연산자 
//event.origin은 지정된 주소를 입력하여 지정된 도메인에서 발신한 것인지 확인합니다.
alert("메시지 전달 받았습니다.");//메시지 수신 후 실행할 스크립트를 입력합니다.
}
}
//현재창에 메시지 이벤트 리스너를 추가 
window.addEventListener("message", receiveMessage); 
</script>
//현재창에 메시지 이벤트 리스너를 추가 
<iframe id="test" name="test" src="http://testsite/innerFrame.jsp"></iframe>

메시지를 주는 쪽인 http://testsite/의 innerFrame.jsp
<script type="text/javascript">
var parent = window.parent; 
if(parent && parent.postMessage){
        //postMessage("전송메시지","전송 도메인") 
parent.postMessage("testMessage",  "*");
}else{
console.log("post Message is not allow"); 
}
</script>

위와 같은 비교적 단순한 구성을 통해 서로 다른 도메인 간의 메시지를 주고받을 수 있습니다.

postMessage 함수는 메시지와 함께 전송할 대상 도메인을 특정할 수 있습니다. 이유는 불필요한 도메인에서 해당 소스를 붙여 메시지를 가로채거나 하는 문제를 방지하기 위해서 입니다.

이 스크립트는 iframe내부 문서와 부모창의 구성을 바꿔서 사용할 수도 있습니다.

postMessage구성 

postMessage(메시지, 대상도메인)

메시지 : 다른 창으로 보낼 데이터를 담는 부분입니다. (구조화된 복제 알고리즘을 통해 정해진 양식으로 변형되어 전송된다고 합니다. )

대상도메인 : "*"을 입력한경우 대상을 특정하지 않고 아무에게나 보내는 것입니다. 공개된 메시지가 되는 것이므로, 중요한 데이터를 보내면 위험할 수 있습니다. 아무나 iframe을 사용하여 메시지를 확인할 수 있으니까요.
사용 예) document.postMessage("메시지", "http://test.kr") 의 형태로 메시지를 보낼경우 http://test.kr이 아닌 도메인에선 해당 메시지를 확인할 수 없습니다. 

SANDBOX 


HTML5에서는 SANDBOX라는 속성이 생겼습니다. 이것을 이용해 크로스도메인 정책을 우회할 수 있다는 인터넷의 일부 문서를 확인했습니다만. 적용결과 실패하였습니다. 안됩니다.

샌드박스 속성과 값 

1. (값없음)                   모든 제한 사항 적용
2. allow-forms               폼 전송을 사용할 수 있습니다.(form.submit())
3. allow-pointer-lock       api를 사용할 수 있습니다.
4. allow-popups             팝업을 사용할 수 있습니다.
5. allow-same-origin        iframe내부의 콘텐츠가 같은 도메인으로 취급됩니다.
6. allow-scripts               스크립트를 사용할 수 있습니다.
7. allow-top-navigation     iframe 내부 콘텐츠가 top.document의 location을 제어할 수 있습니다.

위와 같은 태그 속성이 있고 iframe을 선언할 때 사용하는 코드입니다. 사용방법은 아래와 같습니다.
1. (값없음)  <iframe sandbox src=""> </iframe>
2. allow-forms   <iframe sandbox="allow-forms" src=""> </iframe>
3. 복합 <iframe sandbox="allow-forms allow-top-navigation" src="">  </iframe>

단일 속성을 사용할 수도 있고, 복합 속성을 사용할 수도 있습니다. allow-same-origin  의 경우 서로 다른 도메인일 경우에도 같은 출처로 취급할 수 있다고 설명되어있지만, 실제 사용결과는 다음 오류가 발생합니다.

예) iframe 내에서 top.window.document.reload()를 수행한경우 오류
Uncaught DOMException: Blocked a frame with origin "" from accessing a cross-origin frame.

도메인이 다르기 때문에 발생하는 오류입니다. 이것이 postMessage를 사용하게 된 이유이기도 합니다. 같은 도매인 내에서의 iframe호출은 성공적이었지만, 서로 다른 도메인에 적용한 결과 위와 같은 오류가 발생하여 사용할 수 없습니다.

w3schools에서는 모든 브라우저에서 적용된다고 되어있지만, 실제로 되지 않고 있습니다. 이유를 아시는 분이 계신다면 댓글을 달아주시면 감사하겠습니다.


인터넷 익스플로러 오류 해결 SCRIPT5009: 'JSON'이(가) 정의되지 않았습니다.

최근 여러 사이트에 대한 연동 시스템을 구축하면서 다양한 개발 환경 문제에 직면하게 되었습니다. 그중 ifame을 통한 부모와 자식 창간의 데이터 통신을 하는 과정에서 특정 사이트만 되지 않는 오류를 확인하였는데 이유는 javascript를 해석하는 엔진 버전의 문제인 것 같습니다.


인터넷 익스플로러 오류 SCRIPT5009: 'JSON'이(가) 정의되지 않았습니다.
웹 호환성을 위해 모든 브라우저에서 테스트 하지만 특정사이트만 Internet Explorer에서 지원되지 않는 현상이 있었습니다. 확인하려고 로그를 열어보니 저 빨간색 동그라미 2개가 신경이 쓰입니다. 문서모드7 ? 그리고 우측에 7?

정체는 바로 Internet Explorer 7 버전의 문서모드를 사용하겠다는 선언이  jsp문서에 있었습니다.

<meta http-equiv="X-UA-Compatible" content="IE=7" />

메타 테그로 설정되어있는 이 모드는 일부 html5 기능과 javascript의 동작을 방해하게 됩니다. 최근 트랜드인 웹표준에도 당연히 저해되는 코드입니다. 비슷한 유형의 오류가 발생하고 있다면 해당 태그를 삭제하시면 해결 됩니다.

JSON 데이터 타입은 HTML5에서부터 표준으로 제공되고 있습니다. 웹표준으로 지정되기 이전에는 JSON.ORG를 통해 JSON.JS 라이브러리를 다운받거나, 웹 문서에 링크해 사용했었습니다. https://www.json.org/json-ko.html

html5 라는 웹 표준이 생기면서 여러 라이브러리들이 통합적으로 브라우저에서 지원되는 환경으로 바뀌면서 생기는 오류로, ie도 8버전에서부턴 기본 스크립트로 지원하지만, 하필 7 이하에선 지원하지 않아 생기는 오류입니다.

2017년 3월 21일 화요일

JAVASCRIPT 두 직선의 교차점을 찾는 법

자바스크립트를 통해 GUI를 구성해보기 위해 이런저런 실험을 하는 중인데, 여러 도형간을 연결하는 선을 만들고 싶었고, 해당 선을 만들려다 보니, 각 선분이 교차하는 지점이 매번 도형 내부에 위치되어 보기 싫어지는 현상이 발생했다.

각 도형의 외곽선과, 내부 선의 교차점을 찾아내 첫 도형의 교차점에서 시작해 다음 도형의 교차점에서 종료되는 코드를 만들고 싶었고, 해당 교차점을 찾아내는 것이 의외로 수학의 기하학이라는 수학을 활용해야 하는 복잡한 연산임을 깨닫고, 이런 저런 검색을 하게되었다.

두 직선의 교차점을 찾는 방법을 프로그래밍 코드화 하기 위해 제타위키 에서 나온 교차점 공식을 적용 한 코드를 작성하게 되었다.

두 직선의 교차점 - 제타위키

도형에는 외곽선이 하나가 아닌 여러개이기에,
해당 선분을 빼내어 배열에 넣고 해당 배열의 각 변의 시작점과 종로점의 x축, y축을
각각 (x1, y1, x2, y2)로 입력하였다.

또한 교차를 검사할 대상의 경우 단 하나의 선이므로, 해당 선의 좌표는 x1, y1, x2, y2로 이루어진 하나의 선이다.

/**
 * 기하학 공식 대입 도형의 외곽선과 라인의 크로스포인트를 찾는 역할
 * @param ob1 크로스 포인트를 찾을 도형의 선 집합
 * @param ob2 크로스포인트를 찾을 선
 * @returns
 */

  1. function findCrossPoint(sr, tr){
  2. var pos = [];
  3. for(var i = 0; i < sr.length; i++){
  4. var tmp = sr[i]; 
  5. var p1 = (tmp.x1 - tmp.x2)*(tr.y1 - tr.y2) - (tmp.y1-tmp.y2)*(tr.x1-tr.x2);//분모로 사용됨
  6. // p1 ==0 이면 평행선 또는 일치 이므로 제외(분모)
  7. if(p1 != 0){
  8. var x = 0; 
  9. var y = 0; 
  10. var x = (((tmp.x1 * tmp.y2) - (tmp.y1 * tmp.x2))*(tr.x1 - tr.x2) 
  11. - (tmp.x1 - tmp.x2) * ((tr.x1 * tr.y2) - (tr.y1 * tr.x2))) / p1; 
  12. var y = (((tmp.x1 * tmp.y2) - (tmp.y1 * tmp.x2))*(tr.y1 - tr.y2) 
  13. - (tmp.y1 - tmp.y2)*((tr.x1 * tr.y2) - (tr.y1 * tr.x2))) / p1; 
  14. if((x - tmp.x1) * (x - tmp.x2) <= 0 && (y - tmp.y1) * (y - tmp.y2) <= 0 //교점이 1선분 위에 있고
  15.    && (x - tr.x1) * (x - tr.x2) <= 0 && (y - tr.y1) * (y - tr.y2) <= 0 //교점이 2선분 위에 있을경우
  16. ){
  17. pos.push({ x : x , y : y }) ; 
  18. }
  19. }
  20. }
  21. return pos; 
  22. }

위에서 if문을 통해서 선분 교점의 위치가 음수나 0보다 작거나 같다는 검증을 하는 이유는 선의 전체 거리가 아닌 확장되는 축의 방향을 기준으로 교점을 검사하기에 경우에 따라서 선분이 더 확장될경우 생성되는 교점마저 추출되기 때문이다.


또한 배열에 좌표값을 넣어서 반환하는 이유는, 하나의 선이 두개 이상의 도형 선을 교차하여 통과하는 일이 발생할 수 있기 때문이다. 선하나 제대로 긋겠다고 기하학을 사용하게 될줄은... ㅎㅎ; 고딩떄 수학을 안한것이 새삼 후회하게 된다.