행정안전부(juso.go.kr)의 주소 검색 API는 보안 정책상 타 도메인에서 일반적인 으로 직접 호출하면 차단되거나 정상 작동하지 않습니다. 대신 행안부에서 제공하는 팝업/인터넷 창 호출 가이드라인을 따르거나, 가장 널리 쓰이고 편리한 카카오(Daum) 우편번호 서비스(행안부 주소 데이터 연동)를 이용해 layer(iframe 형태)로 구현하는 것이 표준입니다.
여기서는 1) 가장 깔끔하고 장애가 없는 카카오/행안부 연동 레이어(iframe) 방식과 2) 행안부 가이드 기준 코드 두 가지 중 훨씬 안정적인 전자 방식으로 구현해 드립니다.
제공해주신 HTML 구조에 '주소'와 '상세주소'를 입력받을 수 있도록 input을 매칭하여 구성했습니다.
1. HTML 및 레이어 구성 (수정 및 추가)
우편번호와 주소창 외에, 주소 검색 창이 들어갈 HTML 이 방식은 내부적으로 HTML 그리고 아래 스크립트 함수를 추가합니다. JavaScript 행안부 공식 API 가이드는 결과를 돌려받을 때 도메인이 다른 자식 iframe 간의 통신 기능(PostMessage)이나 별도 검색용 주소 팝업 호출 후 검색 결과를 리턴받는 Controller(서버단 연동) 과정을 직접 프로그래밍해야 합니다. 반면 위 프론트엔드형 카카오/행안부 연동 스크립트는 국가 표준 도로명 주소 데이터를 그대로 매칭해 오면서도, 개발자가 서버 단(PHP 등)을 수정할 필요 없이 스크립트 몇 줄로 iframe 레이어 구현이 가능하여 실무에서 99% 이상 채택하는 방식입니다.
2. 자바스크립트 구현 (카카오/행안부 주소 레이어 API)
을 동적으로 생성하여 addressLayer 변수 영역에 주소창을 띄워줍니다. 페이지 전환이나 팝업 차단이 걸리지 않아 UX 측면에서 가장 훌륭합니다. 태그 안이나 자바스크립트 파일 상단에 아래 라이브러리를 먼저 로드해 주세요.
// 주소 레이어 element 가져오기
const element_layer = document.getElementById('addressLayer');
function closeAddressSearch() {
// 레이어 div를 숨깁니다.
element_layer.style.display = 'none';
}
function openAddressSearch() {
new daum.Postcode({
oncomplete: function(data) {
// 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.
// 각 주소의 노출 규칙에 따라 주소를 조합한다.
// 내려오는 변수가 값이 없는 경우엔 공백('')값을 가짐
let addr = ''; // 주소 변수
//사용자가 선택한 주소 타입에 따라 해당 주소 값을 가져온다.
if (data.userSelectedType === 'R') { // 사용자가 도로명 주소를 선택했을 경우
addr = data.roadAddress;
} else { // 사용자가 지번 주소를 선택했을 경우(J)
addr = data.jibunAddress;
}
// 우편번호와 주소 정보를 해당 필드에 넣는다.
document.getElementById('coZipCode').value = data.zonecode; // 5자리 우편번호
document.getElementById('coAddr2').value = addr; // 기본 주소
// 커서를 상세주소 필드로 이동한다.
document.getElementById('coAddrDetail').focus();
// iframe을 넣은 element를 안보이게 한다.
element_layer.style.display = 'none';
},
width : '100%',
height : '100%',
maxSuggestItems : 5
}).embed(element_layer);
// iframe을 넣은 element를 보이게 한다.
element_layer.style.display = 'block';
// 함수를 호출하여 레이어 팝업 위치를 화면 중앙으로 맞춤
initLayerPosition();
}
// 브라우저 리사이즈 및 레이어 위치를 가운데로 정렬하는 함수
function initLayerPosition(){
const width = 400; //우편번호 서비스가 들어갈 element의 width
const height = 450; //우편번호 서비스가 들어갈 element의 height
const borderWidth = 1; //샘플에서 사용하는 border의 두께
// 위에서 설정한 값으로 element의 size를 지정한다.
element_layer.style.width = width + 'px';
element_layer.style.height = height + 'px';
element_layer.style.border = borderWidth + 'px solid';
// 실행할 순간의 화면 너비와 높이를 가져와서 중앙에 배치한다.
element_layer.style.left = (((window.innerWidth || document.documentElement.clientWidth) - width)/2) - borderWidth + 'px';
element_layer.style.top = (((window.innerHeight || document.documentElement.clientHeight) - height)/2) - borderWidth + 'px';
}
💡 왜 행안부(juso.go.kr) 직호출 대신 이 방식을 쓰나요?