React(SPA)에서 SNS공유 미리보기, SEO적용 방법

정태영·2022년 3월 4일
10
post-thumbnail

SPA에서 SNS공유 미리보기, SEO적용 방법

1. SEO(Search Engin Optimiztion) 이란?

SEO는 검색 엔진 최적화 입니다. 말 그대로 구글이나 네이버같은 사이트에 검색을 하였을 때, 내 사이트가 검색 결과에 더 잘 보이도록 위한 과정이라고 생각하면 됩니다.

구글, 네이버 같은 사이트에서 검색을 하면, 사이트의 meta, html태그 등을 긁어가기 때문에,
검색엔진 알고리즘? 에 좀 더 노출 잘되도록 meta태그, 핵심 키워드 등을 넣어주는 것이 좋습니다.

말 그대로 검색엔진이 내 사이트를 크롤링 할 때 정보들을 잘 가져가도록 만드는 기법이기도 합니다.

2. 알아보게 된 계기

React 서비스를 배포하고, 운영하는 과정에서 마케팅을 위해 SNS공유시 해당 내용을
제목, 설명 등 보여도록 해야하는데, meta태그를 변경 하더라도 SNS에는 변경 되지 않고
어떠한 페이지든 동일한 제목, 설명이 공유 되었다.

그래서 아래(마켓컬리) 사이트처럼 카카오톡에 공유하면 상품명, 설명 등 나오도록 하는 방법을 알아 보았습니다.

SEO 적용 방법

React SEO방법
1. pre-rendring
2. server side rendering (해당내용)

두가지 방법이 있는 것 같습니다.???

1. pre-rendering

빌드할 때 미리 특정 페이지를 랜더링해서, html파일을 만들어 두는 방법

알아보니, react-snap 라이브러리를 통해 해당 라우팅 경로를 지정해주는 방법 인데,
상품페이지가 추가되거나 삭제되고, 수정되는데, 동적페이지는 적용 하기 힘들어 보였서 패스하기로 하였습니다. (잘모름..)

2. server side rendering (nginx)

해당 문제를 해결하기 위해, 찾아본 걸과 nextjs로 마이그레이션 하는 방법이 제일 좋은 방법인 것 같았습니다.

하지만 저는 빠르게 이 문제를 해결하고, 천천히 코드 개선을 하면서 마이그레이션을 준비하기 위해 당장 해결 방법을 알아 보았습니다.

해당 방법은 react 빌드 후, express react를 라우팅 해주는 방식을 사용하고 있습니다. (api포함)

웹 크롤러들은 특정 user_agent를 가지고 내 웹사이트를 접근합니다.

이로인해, 다른 웹 사이트를 별도로 만들어, 해당 SNS링크에 접근하였을 때
user_agent를 체크하여 크롤러인 경우, SEO전용 서버로 redirect 해주는 방식으로 해결을 하면 될 것 같아 진행 하였습니다.

예제 (express, ejs, nginx)를 이용하였다.

서비스 상황에따라 다를 수 있고, express말고 다른 서버를 이용하여도 무관합니다.

기본적으로 라우팅은
http://localhost:3000/page/1
http://localhost:3000/page/2
이런식으로 되어있다고 가정 하겠습니다.

일단 express에서 ejs로 html을 만들어 주기 위해 ejs설치

yarn add ejs

크롤러가 읽을 데이터를 공통적으로 사용하기 위해 seo.ejs를 만들어 주겠습니다.
/server/views/seo.ejs

<!DOCTYPE html>
<html lang="en">
    <head>
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
	      <meta name="title" property="og:title" content="<%= product_info.title %>"/>
        <meta name="image" property="og:image" content="<%= product_info.image %>"/>
        <meta name="description" property="og:description" content="<%= product_info.description %>"/>
        <meta name="twitter:card" content="summary">
        <meta name="twitter:title" content="<%= product_info.title %>">
        <meta name="twitter:image" content="<%= product_info.image %>">
        <meta name="twitter:description" content="<%= product_info.description %>">
    </head>
    <body>
    </body>
</html>

크롤러에게 보여줄 해당 내용을 불러오고 ejs를 이용하여 html파일을 제공할 수 있도록 api를 만들어 줍니다.

server전용 라우팅
http://localhost:3000/api/seo/page/(고유값)
/api/seo/page/seo.js

router.get("/page/:id", async (req, res) => {
  try {
    const groupId = req.params.id; // 해당 공연의 고유값
    const groupInfo = await Page.findOne(
      _id: groupId,
    );
    if (!groupInfo) throw "정보 없음";

	// ejs로 랜더링에 포함될 데이터를 전달해준다.
    return res.render("seo", {
      product_info: {
        title: groupInfo.title,
        image: groupInfo.poster,
        description: "아이겟-좋은자리 선예매",
      },
    });
  } catch (err) {
  	// 해당 데이터가 없을 시 기본값 으로 전달한다.
    console.log(err);
    return res.render("seo", {
      product_info: {
        title: "블로그 오늘시작",
        image: "https://test.naver.com/test.png",
        description: "시작해봅니다.",
      },
    });
  }
});

예를 들어, react의 페이지가
react: http://localhost:3000/page/12341234
server: http://localhost:3000/api/seo/page/12341234

구성을 하고, 만들어둔 server api접속하여 아래 내용처럼 해당 고유 값을 받아오도록 합니다.

위 처럼 잘 데이터가 불러 와진다면 아래 방법으로 진행하면 됩니다.

  1. 크롤러가 내 사이트에 요청 http://localhost:3000/page/12341234
  2. nginx에서 user_agent 체크 후 일반 사용자라면 react, 봇이면 server로 덮어써준다.

nginx설치 방법은 생략하고

etc/nginx/nginx.conf 파일을 수정해준다.

   server {
        listen       80;
        listen       [::]:80;
        server_name  _;
#        root         /usr/share/nginx/html;
        location / {
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_set_header X-NginX-Proxy true;

                proxy_pass http://localhost:3000;

                proxy_redirect off;
                proxy_buffering off;
                client_max_body_size 400M;
                client_body_buffer_size 128k;

        }

        location /page {
                if ($http_user_agent ~* "(Slackbot|facebookexternalhit|Facebot|kakaotalk-scrap|Googlebot|Twitterbot|TelegramBot)") {
                 rewrite ^/(.*)$ http://localhost/api/seo/$1 last;
                }
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_set_header X-NginX-Proxy true;

                proxy_pass http://localhost:3000;

                proxy_redirect off;
                proxy_buffering off;
                client_max_body_size 400M;
                client_body_buffer_size 128k;
        }
    }

제 서비스는
기본적으로 80포트로 요청이 들어오면 3000번의 웹사이트를 보여주도록 셋팅 되어있습니다.

이후 위 내용과 같이
/page/test 요청이 들어왔을때

user_agent 체크 후 크롤러일 경우 아래 내용처럼 server의 내용을 전달 (ejs).
rewrite ^/(.*)$ http://localhost/api/seo/$1 last;

크롤러 요청 ->
http://localhost/page/112 ->
http://localhost/api/seo/page/112 ->
html데이터 수집

으로 진행 됩니다.

참고로 rewrite 사용되는 주소는 실제 내부에서 사용할 수 있는 아이피가 아닌,
외부 주소를 입력해야한다.

마무리 🤗

공부하면서 알아게 되는 지식들을 기록하고 싶어,
이번에 블로그를 처음 시작하게 되었습니다! 🤗

react seo 고민하시는 분들에게 조금이남아 도움이 되었으면 좋겠습니다.

감사합니다.

profile
풀스택으로 개발하고 공부하고 있습니다. 감사합니다.

0개의 댓글