웹 서비스나 쇼핑몰 프로젝트를 개발하다 보면 사용자에게 입력받은 주소를 기반으로 지도에 핀을 표시하거나, 매장 간의 거리를 계산하기 위해 위도와 경도 좌표로 변환해야 하는 상황을 다들 경험해봤을 것이다.
다만 Kakao Developers에서 REST API 키를 발급받아 cURL 요청을 보냈는데 401 Unauthorized 에러가 발생하거나, 응답 결과가 빈 배열(documents: [])로 돌아와서 어디서부터 막혔는지 원인을 몰라 헤매는 경우가 많다.
이번에는 카카오 로컬 API의 주소-좌표 변환(Geocoding) 서비스가 정확히 무엇인지, 왜 헤더 인증 오류가 자주 터지는지, 그리고 PHP cURL을 이용해 안정적으로 좌표 데이터를 추출하는 방법까지 완벽하게 정리해서 소개하겠다.
카카오 로컬 API의 주소 검색 서비스는 지번 주소나 도로명 주소 문자열을 입력받아 해당 위치의 WGS84 좌표계 기준 위도(y)와 경도(x)를 반환해 주는 REST API다.
웹 브라우저 단에서 카카오 지도 JavaScript SDK를 직접 불러와 처리할 수도 있지만, 서버 백엔드 단에서 회원가입 시 주소 데이터를 좌표로 전처리하여 DB에 저장하거나, 서버 간 통신으로 거리를 계산할 때는 REST API 연동이 필수적이다.
실무에서 개발자들이 가장 자주 실수하는 부분은 Kakao Developers 콘솔에서 발급받은 여러 키 중에서 어떤 키를 사용해야 하는지 헷갈려 하는 점과, HTTP 헤더의 인증 포맷 규격을 지키지 않는 점이다.
| 구분 | JavaScript SDK | REST API (PHP/백엔드) |
|---|---|---|
| 사용 키 종류 | JavaScript 키 | REST API 키 |
| 인증 방식 | JS 스크립트 태그내 자동 인증 | HTTP Header (Authorization) 직접 지정 |
| 헤더 포맷 | 불필요 | Authorization: KakaoAK {REST_API_KEY} |
| 주요 용도 | 클라이언트 브라우저 지도 타일 출력 | 서버 측 배치 작업, DB 저장용 좌표 변환 |
cURL 통신 시 오류가 발생하는 이유는 크게 두 가지다. 첫째는 인증 헤더에 Authorization 키워드 뒤 standard OAuth 포맷인 'Bearer'를 습관적으로 붙이는 경우이고, 둘째는 검색할 주소 문자열을 URL 인코딩하지 않고 전송하여 서버에서 파라미터가 깨지는 경우다.
카카오 API는 OAuth2 토큰 기반 요청이 아닌 REST API 키 단독 요청 시 반드시 Authorization 헤더 값으로 Authorization: KakaoAK [자신의 REST API 키] 형태를 요구한다. KakaoAK 뒤에 한 칸의 공백(Space)을 두고 API 키를 넣어야 정상 인식된다.
다음은 주소-좌표 변환을 처리하는 잘못된 구현 예시와 이를 올바르게 보완한 실전 PHP 코드다.
다만 대부분의 개발자들은 습관적으로 Bearer 포맷을 사용하거나 주소 문자열의 공백 처리를 하지 않아 401 에러나 잘못된 HTTP 요청 오류를 겪는다.
<?php
$address = "제주특별자치도 제주시 첨단로 242";
$rest_api_key = "1234567890abcdef1234567890abcdef";
// ✗ 잘못된 URL 전송: 한글 주소 문자열을 그대로 URL에 결합함
$url = "https://dapi.kakao.com/v2/local/search/address.json?query=" . $address;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
// ✗ 잘못된 헤더: Bearer가 아니라 KakaoAK를 사용해야 함
"Authorization: Bearer " . $rest_api_key
));
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>[실행 결과]
HTTP 상태 코드 401 Unauthorized 에러와 함께 `{"msg":"KakaoAK headertoken mismatch.","code":-401}` 메시지가 반환된다.
카카오 규격에 맞춘 KakaoAK 헤더 적용과 rawurlencode()를 통한 파라미터 안전화, 그리고 결과 데이터 예외 처리까지 완벽하게 처리된 코드다.
<?php
function getKakaoGeocoding(string $address, string $restApiKey): ?array {
// 검색어 URL 인코딩 처리
$encodedAddress = rawurlencode($address);
$url = "https://dapi.kakao.com/v2/local/search/address.json?query=" . $encodedAddress;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
// ✓ 올바른 KakaoAK 헤더 포맷 지정
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Authorization: KakaoAK " . trim($restApiKey)
));
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
curl_close($ch);
if ($curlError || $httpCode !== 200) {
error_log("Kakao API Error: [{$httpCode}] {$curlError}");
return null;
}
$data = json_decode($response, true);
// 검색 결과가 없는 경우 예외 처리
if (empty($data['documents'])) {
return null;
}
// 첫 번째 검색 결과의 좌표 정보 추출
$firstMatch = $data['documents'][0];
return array(
'address_name' => $firstMatch['address_name'],
'lat' => $firstMatch['y'], // 위도 (Latitude)
'lng' => $firstMatch['x'], // 경도 (Longitude)
'building_name'=> $firstMatch['road_address']['building_name'] ?? ''
);
}
// 실전 사용 예시
$apiKey = "YOUR_KAKAO_REST_API_KEY";
$searchAddress = "제주특별자치도 제주시 첨단로 242";
$result = getKakaoGeocoding($searchAddress, $apiKey);
if ($result) {
echo "주소: " . $result['address_name'] . "<br />";
echo "위도(Lat): " . $result['lat'] . "<br />";
echo "경도(Lng): " . $result['lng'] . "<br />";
} else {
echo "좌표를 찾을 수 없거나 API 요청에 실패했습니다.";
}
?>[실행 결과]
주소: 제주특별자치도 제주시 첨단로 242
위도(Lat): 33.4507011012351
경도(Lng): 126.570667023023
✗ JavaScript 키를 REST API에 사용: 카카오 디벨로퍼스 앱 설정에 있는 4가지 키(Native, REST API, JavaScript, Admin) 중 반드시 'REST API 키'를 사용해야 한다. 다른 키를 넣으면 401 Unauthorized 에러가 난다.
✓ 헤더 접두사 대소문자 준수: `Authorization: KakaoAK [키]` 형태로, KakaoAK의 대소문자를 정확히 지켜야 한다. `kakaoak` 혹은 `KAKAOAK`로 전송 시 거부될 수 있다.
✗ 상세 건물동/호수 검색 시 검색 실패: 'OO아파트 101동 202호'처럼 너무 디테일한 동/호수 정보가 포함되면 검색 결과(documents)가 빈 값으로 넘어온다. 지번이나 도로명 길 이름까지만 1차 정형화하여 검색하는 로직이 필요하다.
카카오 로컬 API를 통한 주소-좌표 변환은 위치 기반 웹 서비스를 구축할 때 가장 기본적이면서도 핵심적인 기능이다. 잘못된 헤더 포맷이나 인코딩 습관 같은 작은 실수를 바로잡는 것이 안정적인 API 연동 시스템을 만든다는 점을 잊지 말자. 이 글의 PHP cURL 실전 코드를 참고해 프로젝트에 바로 적용해 보면, 401 인증 에러 없는 완벽한 지오코딩 기능을 구현할 수 있을 것이다.