[Trouble shooting] Open API service key is not registered error

정의정·2024년 2월 19일
0

Trouble Shooting

목록 보기
1/3
post-thumbnail

💥 문제 상황


Open API를 활용해 숙박 상품 데이터를 수집하기로 하여 다음과 같이 RestTemplate을 사용해 REST API를 호출했습니다.

 		// ~~ 생략 ~~
    private String makeBaseSearchUrl() {
        String STAY_SEARCH_URI = "/searchStay1";
        return BASE_URL
        	+ STAY_SEARCH_URI 
            + "?serviceKey="
            + SERVICE_KEY
            + DEFAULT_QUERY_PARAMS;
    }
		// ~~생략~~
    private JSONObject getAccommodation(int pageSize, int pageNum) throws JSONException {
        URI uri = UriComponentsBuilder.fromHttpUrl(makeBaseSearchUrl())
            .queryParam("pageNo", pageNum)
            .queryParam("numOfRows", pageSize)
            .build().toUri();
        ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET,
            httpEntity, String.class);
        log.info("숙박 정보 조회");
        return new JSONObject(response.getBody())
            .getJSONObject("response")
            .getJSONObject("body");
    }
	  // ~~ 생략 ~~

그런데 결과를 보니, 아래처럼 SERVICE_KEY_IS_NOT_REGISTERED_ERROR라는 응답이 오고 있었습니다.

분명 활용 신청을 통해 발급받은 서비스 키를 사용했는데도 등록되지 않은 서비스 키라는 응답만 돌아왔습니다.

혹시, 인코딩 문제가 아닐까 의심하기 시작했고, 위 코드의 SERVICE_KEY를 인코딩된 서비스키로도 넣어보고, 인코딩되지 않은 서비스키로도 넣어봤습니다.

하지만, 같은 응답이 돌아올 뿐이었습니다.


💡 원인

원인은 의심한대로 인코딩 문제였습니다.

1. UriComponentBuilder는 공백과 +의 경우 인코딩을 해주지 않습니다.

    private JSONObject getAccommodation(int pageSize, int pageNum) throws JSONException {
        URI uri = UriComponentsBuilder.fromHttpUrl(makeBaseSearchUrl())
            .queryParam("pageNo", pageNum)
            .queryParam("numOfRows", pageSize)
            .build().toUri();
	    // ~~ 생략 ~~

위 코드에서 사용한 UriComponentBuilder공백+를 인코딩해주지 않는다고 합니다. 이 때문에 디코딩된 서비스 키를 UriComponentBuilder를 통해 인코딩한 경우 올바르게 인코딩된 서비스키가 보내지지 않은 것이었습니다.

2. 인코딩된 서비스 키를 사용한 경우 이중 인코딩이 일어납니다.

인코딩된 서비스키를 사용하는 경우 이중 인코딩이 일어납니다. 이 또한 올바르게 인코딩된 서비스키가 보내지지 않습니다.


🪄해결 방안

1. Service Key를 따로 인코딩합니다.

 	// ~~ 생략 ~~
    private String makeBaseSearchUrl() {
        String STAY_SEARCH_URI = "/searchStay1";
        return BASE_URL 
        	+ STAY_SEARCH_URI
            + "?serviceKey="
            + URLEncoder.encode(SERVICE_KEY, StandardCharsets.UTF_8)
            + DEFAULT_QUERY_PARAMS;
    }

URLEncoder.encode()를 사용하여 따로 인코딩해줍시다.

2. UriComponentBuilder의 build() 호출 시 true값을 옵션으로 부여합니다.

    private JSONObject getAccommodation(int pageSize, int pageNum) throws JSONException {
        URI uri = UriComponentsBuilder.fromHttpUrl(makeBaseSearchUrl())
            .queryParam("pageNo", pageNum)
            .queryParam("numOfRows", pageSize)
            .build(true).toUri();
        // ~~ 생략 ~~

이중 인코딩을 막기 위해 UriComponentBuilder의 build() 호출 시 true값을 옵션으로 부여합니다.

💭 느낀 점

Open API를 사용할 때 서비스 키와 함께 요청 URI 인코딩에 유의해야 한다는 것을 느낄 수 있었고, UriComponentBuilder의 인코딩 특징에 대해 알 수 있어 유익했습니다.

profile
배움 기록

0개의 댓글