nodejs 를 통해 웹링크 미리보기 만들기(open-graph-scraper)

예리에르·2023년 2월 20일
2

React

목록 보기
15/17
post-thumbnail
post-custom-banner

게시물을 보다보면 문구에 포함된 링크의 미리보기를 제공해주는 경우를 본적이 있다. 데이터를 불러오기 위해서는 URL에 OGTag가 있어야한다.

OGTag란?

어떤 HTML 문서의 메타정보를 쉽게 표시하기 위해서 메타정보에 해당하는 제목, 설명, 문서의 타입, 대표 URL 등 다양한 요소들에 대해서 사람들이 통일해서 쓸 수 있도록 정의해놓은 프로토콜이다.

URL링크를 올렸을때, 크롤러가 메타데이터의 og로 지정된 title, description, image등의 정보를 긁어와서 표시한다.

open-graph-scrper

URL의 Open Graph 정보를 가져오기 위해 open-graph-scraper 패키지를 사용했다.

const ogs = require("open-graph-scraper");

...

const requestOpenGraphScraper = (req, res, urlData, url) => {
   return ogs({
       url: url,
       peekSize: 30000000,
   })
       .then((data) => {
           urlData.push({...data.result, url: url});
           res.status(200).json({data: urlData});

       })
       .catch((err) => {
           res.status(400).json({message: err});
       });
};

OG 데이터를 얻고 싶은 url을 넘겨주면 해당 url의 메타데이터를 받아올수있다.

문제점1. bit.ly와 같은 단축URL

표준의 URL의 경우 쉽게 데이터를 받아올 수 있지만, 단축 URL은 예외의 경우였다. 불러오는 코드를 작성하면서 먼저 페이스북 페이스북 공유 디버거 를 많이 사용했다.

디버거를 통해 2번의 redirect를 통해 표준 url을 얻어내는 과정을 확인 할 수 있었다.

HTTP 301과 302 redirce의 차이

301과 302는 사용자를 새로운 URL로 이동시키는 코드이다. Redirection 상태코드들은 클라이언트를 지정된 위치로 이동시키거나 참조하게 하는 등의 동작을 말한다.

301 리다이렉트
301 혹은 영구이동(Permanently Moved)이라고도 한다. 해당 URL이 영구적으로 새로운 URL로 변경되었음을 나타낸다.
그래서 301은 웹사이트의 도메인을 변경했거나 새로운 URL 구조로 개편했을 때 사용할 수있다. 검색에진은 과거 URL의 페이지랭킹과 평가점수(모든 SEO값)를 새로운 URL로 이동시킨다.

302 리다이렉트
302 혹은 임시이동(Temporarily Moved)라고도 한다. 요청한 리소스가 임시적으로 새로운 URL로 이동했음을 나타내고 색엔진은 페이지랭킹이나 링크에 대한 점수를 새로운 URL로 옮기지 않으며 기존 URL을 그대로 유지한다. 컨텐츠만 새로운 URL에서 조회하도록 한다.

다시 내용으로 돌아와 이런경우 2번의 requeset를 보내는 로직이 추가되어야한다.

const requestRedirect = (req, res, urlData, url) => {
    request({
        url: url,
        followRedirect: false
    }, function (error, response, body) {
        const redirectURL = response.headers.location;
        if (response.statusCode == 301 || response.statusCode == 302) {
            requestRedirect(req, res, urlData, redirectURL);
        } else if (response.statusCode === 200) {
            requestOpenGraphScraper(req, res, urlData, url);
        }
    })
};

상태코드가 301이거나 302일 때는 요청을 보내는 함수를 재귀시키고 200 일때는 OpenGraphScraper 요청 하는 함수를 실행하는 방법으로 코드를 작성하였다.

문제점2. 네이버 블로그

네이버 블로그를 공유하면 원했단 해당 블로그 포스트 내용이 오지 않았다.

페이스북 공유 디버거를 확인해본 결과 URL을 그대로 요청하면 되는것이 아니라 위 사진처럼 형식에 맞춰서 요청을 보내야했다. 처음에는 클라이언트에서 함수로 만들어서 문자열로 바꿔 요청해지만 서버에서 처리하는 측면이 나을꺼라고 생각해서 코드 방향을 바꾸었다.


인썸니아를 통해 링크를 공유하면 response에 rawHtml이 담겨오고 그안의 iframe을 통해 요청 URL을 가져올수 있을알 파악했다.

const getNaverBlogStandardURL = (htmlBody) => {
    const noEnter = htmlBody.replace("\n", "");
    const dom = new JSDOM(noEnter);
    const iFrameTag = dom.window.document.querySelector("#mainFrame");

    if (iFrameTag.getAttribute('allowfullscreen')) {
        return `https://blog.naver.com${iFrameTag.getAttribute('src')}`;
    }
};

네이버의 경우 처리를 하는 함수를 추가하였다.

최종코드

const apiMeta = {
    getMetaData: async (req, res) => {
        const urlData = [];
        const reqUrl = req.body.urlList[0];

        if (reqUrl.includes("bit.ly")) {
            requestRedirect(req, res, urlData, reqUrl);
        } else if (reqUrl.includes("blog.naver")) {
            const options = {uri: reqUrl};
            request.get(options, (error, response, body) => {
                const htmlBody = response.body;
                const standardURL = getNaverBlogStandardURL(htmlBody);
                requestOpenGraphScraper(req, res, urlData, standardURL);
            })
        } else {
            requestOpenGraphScraper(req, res, urlData, reqUrl);
        }
    },
};

후기

현재 개발중인 React는 CSR이라서 서버를 통해 데이터를 가져오는 방식을 node.js를 따로 만들어 구축해서 가져오는 방식을 사용했다. 하지만 SSR Next라면 좀 더 수월했을 것 같다는 생각을 했다. 현재 회사에서는 굳이 SSR을 사용하는 경우가 없어서 필요성을 못느꼈는데 이번 개발을 통해 SSR의 쓰임을 다시 알 수 있었다.

참고
https://velog.io/@kirin/OG-Open-Graph%ED%83%9C%EA%B7%B8
https://nsinc.tistory.com/168
https://inpa.tistory.com/entry/HTTP-%F0%9F%8C%90-301-vs-302-%EC%83%81%ED%83%9C-%EC%BD%94%EB%93%9C-%EC%B0%A8%EC%9D%B4%EC%A0%90-%F0%9F%92%AF-%EC%99%84%EB%B2%BD-%EC%A0%95%EB%A6%AC

profile
궁금한 프론트엔드 개발자의 개발일기😈 ✍️
post-custom-banner

0개의 댓글