text/JavaScript

CORS 에 대한 간략한 설명과 img 태그를 채우기 위한 삽질

hoonzii 2022. 6. 27. 22:47
반응형

오늘 회사에서 한 일에 대해 다시금 생각해본다.

저번에 올린 블로그 글 결과를 토대로 뉴스 군집화를 해냈다. (done이라는 뜻. complete가 아니라…)

 

점진적 뉴스 군집화 하기 (incremental news clustering)

요즘 관심 가지던게 하나 있는데 바로 점진적 문서 군집화 무슨 소리냐 뉴스의 경우, 계속 써지고 발간되고 사람들한테 제공된다. 지금까지 내가 해온건 어떤 시간대 (가령, 하루단위) 뉴스를 군

hoonzi-text.tistory.com

결과를 그럴듯하게 보여주기 위해 해당 뉴스가 가진 썸네일 데이터를 가져와야 했는데

다행히도 우리회사 데이터는 해당 뉴스에 등장 하는 이미지 데이터 역시 수집이 되어 있었다.

그냥 조회만 하면 됐다. (아래는 결과 예시)

양현종 관련 기사들이 군집화 된 결과

문제는 방송사의 경우 이미지가 아니라 동영상으로 존재했는데… 이미지가 없다보니 데이터 상에도 없고,

데이터에 없다보니 <img> 태그에 들어가는 값도 존재하지 않았기에

사진 란에 아무것도 표시되지 않는 문제가 있었다.

 

어떻게 하나 생각하다가 생각난 게 바로… <meta> 태그!

검색엔진 최적화를 위해 페이지의 요약을 적어놓은 태그라고 보면 되는데

meta 태그 예시

사진을 자세히 보면 meta 태그의 attribute로 어떤 정보인지, 실제 데이터값으로는 뭔지 (contents) 에 대해 가지고 있는것을 볼 수 있다.

그럼 로직을 세워보자.

  1. 이미지 데이터가 존재하지 않을 경우
  2. 기사 url 을 통해 meta태그를 조회해서 가져온다.

계획 ok, 로직 ok

해당 이미지는 html에 배치할때 나타나니깐 js로 구현해보자. 라는 그럴듯한 계획을 세웠다.

 

이미지를 가져오기 앞서 예시로 접근이 되는지 먼저 검증해보자.

ajax를 이용해 네이버 기사를 가져오는 간단한 코드다.

이 코드를 돌리는 곳은 현재 내 로컬(클라이언트) 이고, 네이버에 “해당 url 데이터를 주세요” 하고 요청하는 거다.

$.ajax({
    type:"GET",
    url : "https://n.news.naver.com/mnews/article/020/0003436661?sid=100",
    success : function(response){
        console.log(response);
    },
    error : function(e){
        console.log("error");
    },
});

결과는 ...

Access to XMLHttpRequest at 
'https://n.news.naver.com/mnews/article/020/0003436661?sid=100' 
from origin '{회사페이지}' 
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' 
header is present on the requested resource.

CORS 정책에 의해 block 됐다고 뜬다.

CORS가 먼데?!?!

 

cors란 무엇인가?

출처 : https://developer.mozilla.org/ko/docs/Web/HTTP/CORS

출처가 다른 곳에서 보내진 요청에 대해 자원 접근 허락이라고 볼 수 있다.

보안 상의 이유로 브라우저는 클라이언트 단의 js의 요청은 같은 출처에 대해서만 허락하고

나머지는 전부 block 시키는데 이것을 허용 시켜주는게 CORS라고 할 수 있다.

(예외로는 link 태그와 img 태그에서는 가능하다고 한다!)

 

그럼 질문이 생긴다.

출처가 같다? 다르다? 출처는 무엇인데?

출처 : https://evan-moon.github.io/2020/05/21/about-cors/

클라이언트 단에서 네이버 기사에 접근하기 위해서 https://, naver.com/, {port} 가 같아야 하는구나!

(→ same origin policy 라고 한다.)

CORS 정책은 위 SOP의 불편함을 해소하기 위해 만들어진 정책이구나~

대충 뭔지 감 잡았다.

 

그렇다면 JS로 CORS 정책을 이용해 값을 가져오는 방법이 있을까?

SOP를 뚫기 위한 시도

1. orgin을 설정해 보내보자!

$.ajax({
    type:"GET",
    url : "https://n.news.naver.com/mnews/article/020/0003436661?sid=100",
    header : {
        origin : "{회사페이지}",
    },
    success : function(response){
        console.log(response);
    },
    error : function(e){
        console.log("error");
    },
});

결과는 당연히 위 오류와 동일하다

네이버 서버에서 보내주는 “Access-Control-Allow-Origin” 값이 origin과 다르니… (당연하다…)

 

2. 크롬 확장 프로그램 설치?

내 로컬에서 돌아가는것과 상관없이!! (다운도 안함)

다른 사람 컴퓨터에는 해당 확장프로그램을 일일히 다운받으라고 할 수 없기 때문에 기각~

 

3. dataType : JSONP 요청

 

출처 : https://brunch.co.kr/@adrenalinee31/1

ajax의 return type을 JSONP 로 명시하면??

$.ajax({
    type:"GET",
    url : "https://n.news.naver.com/mnews/article/020/0003436661?sid=100",
	dataType: 'jsonp',
    success : function(response){
        console.log(response);
    },
    error : function(e){
        console.log("error");
    },
});

역시 마찬가지로 안된다. css나 js를 요청하는게 아닌 html 페이지를 요청하고 있기 때문이다. 이 역시 SOP 정책에서 벗어나지 못한다.

 

4. 마지막 시도 java 단에서 처리…

클라이언트 단에서 처리가 안된다는건 여러 시도를 통해 알게 되었다.

구글링해서 나온 결과들은 대부분 서버에 올려놓은 코드(내가 작성한) 와

현재 내 로컬 간의 SOP가 위배되어 일어난 일에 대해 서술하기 때문에

 

1. CORS 를 설정하거나

2. NO-CORS로 꺼버리거나

3. Access-Control-Allow-Origin : * (모두 허용)

하는 등의 방식으로 SOP를 벗어나고 있었다.

 

나는 내 서비스에서 다른 외부 회사 데이터에 접근하는 거니 해당 사항이 없다…

그렇다면 이미지가 없는 기사 데이터인 경우, 해당 기사의 meta데이터를 가져오는 API를 구성한다음

값을 조회한 후 채워서 반환하게 만들면 되겠다고 결론을 냈다. (새로운 API를 만든다고 보면 될듯 ㅠ)

로직은 이러하다.

 

현재 페이지에서 img null!! -> ajax (현서버) -> 서버내 로직 -> meta img call

그림으로 보면 이렇다. 쩨끔한 API

JS 요청

if(articleImg == null) { // 이미지가 존재하지 않는다면!
    let ask_url = "{path}/imgURLReturn.jsp"; // 해당 기사에 대한 이미지를 조회하는 API
    $.ajax({
        type : "POST", 
        url : ask_url,
        dataType : "text", // 기사 썸네일은 url 텍스트~
        data : {
            "url" : rep_url, // 기사 url을 파라미터로 같이 넘겨줍시다.
        },
        success : function(response) {
            //img tag 에 넣기 
        },
        error : function(e) {
            // error 처리
            console.log("error",e);
        },
    }) 
}

 

JSP {imgURLReturn.jsp} 요청

<%
request.setCharacterEncoding("UTF-8");

String url = request.getParameter("url"); // 파라미터로 넘겨받은 url
// img 가져오기
imagePr ip = new imagePr ();
String imgUrl = ip.imgSrcReturn(url); // 해당 url에서 기사 썸네일을 가져오는 함수

out.print(imgUrl); // 반환받은 기사 썸네일 이미지 주소 반환
%>

 

JAVA {imagePr} 클래스의 함수

public String imgSrcReturn(String url) throws IOException {
    Document doc = Jsoup.connect(url).get(); // JSOUP을 통해 html 요소 조회
    Elements head = doc.select("head");
    Elements meta = head.select("meta[property=\"og:image\"]"); // 썸네일 이미지 주소 가져오기
    return meta.attr("content");
}

 

결과는 군집화된 모든 기사에서 이미지 빵꾸난거 없이 잘 보이게 됐다~~~

(오래오래 행복하게 살았답니다~~~)

 

결론

이번 에러 상황을 통해 CORS 정책이 무엇인지 알고 넘어가게 되어 기분이 좋다.

(덕분에 블로그에 글도 쓰고 말이지)

반응형