og 이미지 크롤링을 어디서 해야할까?
개발 이야기아는 동생들이 최근에 프로젝트를 진행하면서 SNS를 만든다 하더라. 미리 만들어둔 플로우 시안을 피그마로 살펴보다가 좀 어려워 보이는걸 발견하게 되었다.
주위에서 흔히 볼 수 있는 인스타그램이나 트위터류 서비스 같은데, 글에 타 서비스의 미리보기 이미지 같은게 보이더라. 서버 스택은 자바 스프링이고, 프론트엔드는 리액트가 아니라 그냥 스태틱. 가령 아래와 같은 기능을 만든다 보면 된다.
사용자가 글을 쓸 때 유튜브나 뭐든 링크 하나를 글 내용에 추가를 하면, 서비스 측에서 알아서 판단해서 미리보기를 나중에 함께 보여주는 것이다. 근데 사용자에게 보여주는 시점에서 미리보기 이미지를 대체 어떻게 가져올까에 대해 두가지 생각이 들었다.
프론트엔드에서 처리하는 것과 백엔드에서 처리하는 것 두가지가 있을것 같은데?
우선 서버에서 API로 글 목록을 리턴한다. 가령 아래와 같지.
// GET /posts
data: [
{
title: '글 제목',
preview: '글 내용은 이러저러한데..',
outerLink: 'https://aaa..',
},
{
title: '글 제목2',
preview: '글 내용2은 이러저러한데..',
outerLink: 'https://bbb..',
},
]
그러면 프론트엔드에서 리스트를 순회하며 Post 컴포넌트를 그린다. 각각의 컴포넌트를 마운트하는 시점에서 저 outerLink를 GET 해다가 <head>
에서 og:image를 추출하는걸까? 글쎄.. 그러면 CORS 두들겨 맞을것 같은데? 다른 도메인에서 저 외부 도메인의 이미지를 가져와서 보여주는거잖아?
그리고 외부 도메인의 이미지를 갖다 쓰는 것이니만큼 안전하지가 않다. 해당 이미지가 야짤 같은걸로 교체가 될 수도 있고, 외부 서비스가 망가져서 이쪽에 영향을 줄 수도 있는거지. 혹은 외부 서비스가 서버리스로 구성되어있는데 콜드 스타트 걸리거나, 아니면 집에 남아도는 NAS에 설치되어 있던가, 뭐 서버가 똥컴이라던가 이런저런 이유로 로딩 15초가 막 넘어가고, 타임아웃 걸리고 그거 핸들링하고 지저분한 일이 발생할 수도 있지.
더 징그러운걸로는 XSS 공격이 있을 수 있겠다. og:image에 SVG 파일을 넣고, 그 안에 <script>
를 사용해서 자바스크립트를 실행하게 한다면? 그래서 이 작업은 프론트엔드가 아니라 백엔드에서 해야 할것 같더라. 자세한 방법이나, 가능 여부는 더 알아봐야 할 것 같고.. (나는 백엔드 잘 모른다)
자 그럼 기능을 백엔드에서 구현해야 한다면..
사용자가 글 내용에 url을 박아서 서버에 포스트 하면, 서버는 그 url을 추출해서 알아서 해당 경로의 메타태그를 가져오게 된다. 이 타이밍에 타 서비스에서 우리 서버의 유저 에이전트를 보고 “너 크롤러야? 크롤러 꺼져! 우리는 브라우저만 받는다” 할 수 있기 때문에 UA를 변조해야 할 수 있다.
지금 보고 있는 내가 만든 서비스에서도 DPreview의 xml 파일을 불러올 때 UA를 변조해서 사용하고 있다.
찾아보니까 전용의 이런 라이브러리도 있더라.
https://github.com/samholmes/node-open-graph
코드 열어보니 라이브러리가 하는 일은 매우 단순하다.
- UA 변조
- 파싱해서 이쁘게 보여주기
여기서 파싱을 위해 cheerio까지 사용하는걸 보니 라이브러리가 하는 일에 비해 가볍지는 않다. 근데, 생각해보면 내가 axios를 쓰던 fetch를 쓰던, 아 노드니까 request 같은걸 쓰는것 같더라구. 암튼.. 갖고온 내용은 텍스트니까.. 결국 파싱을 해야 하잖아? 그럼 어차피 cheerio든 뭐든 쓸 수 밖에 없겠군.. 아니면 직접 파서를 만드는 귀찮음이 들겠지.
그리고 og:image URL을 찾았으면 그걸 다운받아서 우리측에 사본을 만들어놔야 할거다. 상대 URL에서 이미지를 초대형으로 넣어놨을 수도 있으니 우리측 규칙에 맞게 리사이즈를 해야 할 수도 있고.. 그럼 그 사본에 대한 URL을 DB에 넣어놔야겠지?
페이스북의 경우 이렇게 디버거가 있고, 이미 한번 공유된 글에 대해 캐시를 날리는 기능이 있다. 카카오톡도 같은게 있다. 아마 이 친구들은 DB 테이블을 하나 만들고 키 값으로 url을 넣어놨지 싶다. 물론 나는 백엔드는 잘 모른다. 대충 이렇지 않을까 생각해본거다.
어 Next의 경우에는 백엔드가 따로 안들고 있어도 프론트 서버에서 작업을 하니까 프론트엔드 혼자서만 가능하기도 하다. 물론 공유된 상대방 서비스가 느리다면 그에 맞춰서 우리 프론트가 뜨는 속도도 느려지겠지.. 여튼 결론은, 이 작업은 백엔드에서 해야 하는 작업이란거다.
…
하지만 아는 동생들에게 물어본 결과, 저렇게 외부 사이트 이미지를 가져오는게 아니라 자체 SNS 글을 퍼가기 했을 경우에 나오는 기능이라더라. 내부 데이터니만큼 DB랑 API단에서 알아서 잘 가공해서 프론트로 보내줄 수 있을것 같았다. 휴, 다행이군.. 자네들이 하기에는 너무 어려워보였다네..
아무튼 문득 떠올라서 마구마구 생각해본 내용을 적어보았다.
ps. UA 변조를 프론트엔드에서 하는 것은 옛날 기준으로 크롬에선 안되고 사파리와 파이어폭스에서는 가능했다더라. 아마 요즘은 안될것 같다. 크롬에서 안되면 같은 엔진 돌려쓰는 Edge 같은데서도 안되겠지.