API 호출, 크롤링 우회

박우영·2023년 8월 6일
0

트러블 슈팅

목록 보기
17/19

개요

프로젝트는 특정 api, 정보에 대해 의존적입니다. 따라서 해당 정보를 가져와야하는데 제 개인 Local 환경에서는 잘 되지만 GKE 환경에서 되지 않는 Issue 가 발생하였습니다.

Error Msg

[http-nio-8084-exec-1] [2023-08-05 23:40:28,741] [ERROR] [SolvedCrawling.java:136] - <html><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>ERROR: The request could not be satisfied</title>
</head><body>
<h1>403 ERROR</h1>
<h2>The request could not be satisfied.</h2>
<hr noshade="" size="1px">
Request blocked.
We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
<br clear="all">
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
<br clear="all">
<hr noshade="" size="1px">
<pre>Generated by cloudfront (CloudFront)
Request ID: -ok_4ED_rixCpeCLsp6ytvEtEjyMwZSMUb2VxVa10USNMDizAGzXbg==
</pre>
<address>
</address>
</body></html>

Code

  • RestTemplate 설정
@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate;
    try {
        restTemplate = new RestTemplate(clientHttpRequestFactory());
    }catch (Exception e){
        restTemplate = new RestTemplate();
    }
    restTemplate.setInterceptors(Collections.singletonList(
            (request, body, execution) -> {
                HttpHeaders headers = request.getHeaders();
                headers.setContentType(APPLICATION_JSON);
                headers.setAccept(Collections.singletonList(APPLICATION_JSON));
                headers.add(HttpHeaders.ACCEPT, "application/json");
                headers.add(HttpHeaders.USER_AGENT, "Mozilla/5.0");
                return execution.execute(request, body);
            }
    ));
    return restTemplate;
}

private HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {
    return new HttpComponentsClientHttpRequestFactory();
}
  • API 요청
public String getSubject(int problemId) throws Exception{
    String jsonString = null;

    try {
        jsonString = restTemplate.getForObject("https://solved.ac/api/v3/problem/show?problemId=" + problemId, String.class);
    }catch (Exception e){
        e.printStackTrace();
        throw new HttpResponseException("문제 정보를 가져오는데 실패했습니다.");
    }

    JSONParser jsonParser = new JSONParser();
    Object jsonObject = null;
    try {
        jsonObject = jsonParser.parse(jsonString);
    } catch (ParseException e) {
        e.printStackTrace();
    }

    JSONObject jsonBody = (JSONObject) jsonObject;

    return jsonBody.get("titleKo").toString();
}
  • 크롤링
public BaekJoonDto profileCrawling(String baekjoonId) throws IOException, InterruptedException {
    WebDriver driver = setDriver();
    sleep(1000);
    driver.get(SOLVED_BASE_URL + SOLVED_PROFILE + baekjoonId);

    By solvedListBy = By.xpath("//*[@id=\"__next\"]/div[3]/div/div[6]/div[3]/div/table/tbody");
    sleep(1000);
    try {
        wait(driver, solvedListBy);
    } catch (TimeoutException | NoSuchElementException e) {
        log.error("{}", driver.getCurrentUrl());
        log.error("{}", driver.getPageSource());
        throw new CrawlingException("사용자 정보를 찾을 수 없습니다. 다시 시도해 주세요");
    }
    WebElement elements = driver.findElement(solvedListBy);
    WebElement webElement = elements.findElement(By.className("css-1ojb0xa"));
    int bronze = getUserSolvedCount(webElement, By.xpath("//*[@id=\"__next\"]/div[3]/div/div[6]/div[3]/div/table/tbody/tr[1]/td[2]/b"));

    driver.quit();
    return new BaekJoonDto(bronze);

이렇게 설정하였고 StackOverflow 에 있는 질문도 찾아보고 직접 질문도 올려봤습니다.
질문게시글

이미 조치를 해봤던 내용들밖에 보이지않았고, 이걸 사용할 수 없다면 프로젝트의 방향성을 잃어버리기 때문에 포기할 순 없었습니다.

확인1

먼저 GKE 내부에서 외부 네트워크의 문제인이 확인하기 위해 Test 용으로 임의의 사이트의 정보를 가져와 봤습니다

GKE -> 외부 O

확인2

방화벽 문제인가 싶어 방화벽을 전부 열어두고 조치를 해봤습니다.

방화벽 Issue X

확인3

프로토콜 http https 차이?
제 개인 Local 환경에서는 정상적으로 되기때문에 프로토콜 은 아니라고 생각했습니다.

프로토콜 ?

확인4

csp 마다 약간의 차이가 있기때문에 벤더락을 우려하였습니다. 따라서 AWS, NCP 에서도 진행을 해보고자 했습니다.

호출 성공하였습니다. 프로젝트의 Issue를 해결이 우선이라 판단하여 해당 서비스는
EC2로 구성하여 멀티클라우드로 프로젝트 아키텍처를 변경이 불가피 했습니다.

최대한 Kafka를 활용하여 통신을 구성하고 불가피한 정보는 Rest 통신을 하여 구성하고자 리팩토링을 진행 하였습니다.

멀티클라우드 전환

외부 API 와 크롤링 이 안되던 것들의 문제는 AWS로 전환하면 해결되는것을 확인했으니 1개의 CSP를 이용하는것이 아닌 멀티 클라우드로 전환을 해야했습니다.

AS-IS

TO-BE

서비스간의 통신은 event 처리에 의한것은 kafka 로 처리하고 그 외의 member들의 정보를 받아오는것들은 Gateway를 통해 받아옵니다.

0개의 댓글