목차
1. 웹 개발에서의 리다이렉션
웹 개발에서 리다이렉션은 사용자를 한 웹 페이지나 URL에서 다른 페이지나 URL로 자동으로 보내는 방법을 말한다. 이는 주로 사이트 구조가 변경되었을 때, 오래된 URL을 새 URL로 매핑하기 위해 사용되며, 사용자 경험을 유지하고 SEO(검색 엔진 최적화)에 유리하게 작용한다.
1.1 리다이렉션의 중요성
- 사용자 경험 보장: 사용자가 오래된 링크를 통해 웹사이트에 접근할 때 오류 페이지(예: 404 Not Found)가 아닌 새로운 페이지로 자동 유도되어 사용자 경험을 유지한다.
- 검색 엔진 최적화 (SEO): 대표적인 리다이렉션 유형인 301은 "영구적인 리다이렉션"으로 간주되며, 검색 엔진은 이를 통해 오래된 페이지의 검색 엔진 순위와 권한을 새 페이지로 전달한다. 이는 새 페이지가 검색 결과에서 빠르고 효과적으로 노출되도록 한다.
- 링크 가치 유지: 외부 웹사이트에서 오래된 URL로의 링크가 있을 경우, 리다이렉션을 통해 그 링크의 가치를 새 URL로 이전한다. 이는 웹사이트의 전체적인 온라인 가시성과 권위를 유지하는 데 도움이 된다.
1.2 프론트엔드 라우팅 vs 서버 측 리다이렉션:
사실 페이지라는 것이, 클라이언트에서 하드코딩으로 페이지를 이동시키기만 해도 되는 것이다. 예를 들어, 유저가 old product 페이지 진입 시 new product 페이지로 이동하게끔 클라이언트에서 단독으로 처리해도 사용자 경험에는 이상이 없다. 다만 웹 개발 시 일반적으로 서버를 통해 리다이렉션 로직을 구성하는 것이 권장되는데, 그 이유는 다음과 같다.
클라이언트 측 리다이렉션 하드코딩의 문제
클라이언트 측에서 JavaScript를 이용하여 리다이렉션을 구현할 수도 있지만, 몇 가지 단점이 있다:
- 검색 엔진 처리: 모든 검색 엔진이 자바스크립트를 실행하고 이를 올바르게 처리하는 것은 아니므로, 클라이언트 측 리다이렉션은 검색 엔진에 의해 인식되지 않을 수 있다.
- 페이지 로딩 지연: 자바스크립트 실행을 기다려야 하므로 리다이렉션이 완료까지 페이지 로딩 시간이 길어질 수 있다.
- 접근성 문제: 자바스크립트가 비활성화된 환경에서는 리다이렉션이 작동하지 않을 수 있다.
서버 측 리다이렉션 지정 처리
서버 측에서 리다이렉션을 처리하는 것은 SEO에 있어서 일반적으로 더 바람직하다:
- 검색 엔진은 서버 측 리다이렉션을 정확히 인식하고 색인화 과정에서 이를 올바르게 처리할 수 있다.
- URL 권한 이전: 예를 들어, 301 리다이렉션은 '영구적'으로 간주되어 기존 페이지의 검색 엔진 순위와 권한을 새 페이지로 이전할 수 있다. 302는 일시적으로 간주되어, 장기간에 걸쳐서는 같은 효과가 없다.
- 보다 효율적인 크롤링: 검색 엔진이 클라이언트 측 코드를 실행하지 않고도 리다이렉션을 따를 수 있으므로, 자원을 더 효율적으로 사용할 수 있다.
2. 대표적인 리다이렉션 유형
다음은 300번대 HTTP 상태 응답 코드를 통해 서버에서 리다이렉션을 수행하는 방법이다.
2.1. 301 리다이렉션 (영구 이동):
301은 URL이 영구적으로 변경되었을 때 사용하는 방식이다. 검색 엔진이 새 URL로 순위 정보를 전송하고, 이전 URL에 더 이상 유효하지 않은 것으로 간주한다. 다음은 예전 상품 페이지에 대한 접속 시 새로운 상품 페이지로 이동시키는 301 예시 코드이다. 이미 없어진 페이지에 대한 작업을 리다이렉션 작업을 해줘야 하는 이유는 사용자가 이 페이지를 이미 즐겨찾기를 해뒀거나, 검색엔진에서 색인 처리를 해둔 경우가 있기 때문이다.
서버 코드 (Node.js)
// SERVER
const express = require('express');
const app = express();
const port = 3000;
// 기존 상품 페이지 경로
app.get('/old-product', (req, res) => {
// 새 상품 페이지로 영구 리다이렉션
res.redirect(301, '/new-product');
});
// 새 상품 페이지 경로
app.get('/new-product', (req, res) => {
res.send('Welcome to the New Product page!');
});
app.listen(port, () => {
console.log(`Server running on <http://localhost>:${port}`);
});
클라이언트 코드 (자바스크립트)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Product Redirection</title>
</head>
<body>
<button id="redirectButton">Go to Old Product</button>
<script>
document.getElementById('redirectButton').addEventListener('click', function() {
fetch('http://localhost:3000/old-product', {
redirect: 'follow' // 리다이렉션을 자동으로 따르도록 설정
})
.then(response => {
if (response.redirected) {
console.log('Redirected to:', response.url);
}
return response.text();
})
.then(text => console.log(text))
.catch(error => console.error('Error:', error));
});
</script>
</body>
</html>
2.2. 302 리다이렉션 (임시 이동):
리다이렉션 302는 클라이언트가 요청한 리소스가 일시적으로 다른 URL로 이동되었음을 나타내는 HTTP 상태 코드다. 이 예시에서는 자바스크립트 클라이언트가 서버에 요청을 보내고, Node.js 서버가 302 상태 코드로 응답하여 클라이언트를 다른 URL로 리다이렉션하는 과정을 설명한다. 다음은 product 페이지 접속을 special-offer 페이지로 이동시키는 상황의 예시 코드이다.
서버 측 코드 (Node.js)
const express = require('express');
const app = express();
const port = 3000;
// 상품 페이지 경로
app.get('/product', (req, res) => {
// 특별 할인 페이지로 리다이렉션
res.redirect(302, '/special-offer');
});
// 특별 할인 페이지 경로
app.get('/special-offer', (req, res) => {
res.send('Welcome to the Special Offer page!');
});
app.listen(port, () => {
console.log(`Server running on <http://localhost>:${port}`);
});
이 코드에서 /product 경로로 들어온 요청은 /special-offer 경로로 리다이렉션된다.
클라이언트 측 코드 (자바스크립트)
클라이언트 측에서는 fetch API를 사용하여 서버에 요청을 보내고 리다이렉션이 처리되는 과정을 확인할 수 있다.
fetch('<http://localhost:3000/product>', {
redirect: 'follow' // 리다이렉션을 자동으로 따르도록 설정
})
.then(response => {
if (response.redirected) {
console.log('Redirected to:', response.url);
}
return response.text();
})
.then(text => console.log(text))
.catch(error => console.error('Error:', error));
이 클라이언트 코드는 서버에서 보낸 리다이렉션 응답을 자동으로 따라가며, 최종적으로 리다이렉션된 페이지의 내용을 콘솔에 출력한다. 리다이렉션이 성공적으로 수행되면 response.redirected가 true가 되며, response.url은 리다이렉션된 페이지의 URL을 보여준다. 이러한 과정을 통해 사용자는 상품 페이지에서 자동으로 특별 할인 페이지로 이동할 수 있다.
2.3. 303 리다이렉션 (See Other):
HTTP 상태 코드 303 ("See Other")는 클라이언트에게 요청된 리소스가 다른 URI에 있음을 알리고, 클라이언트를 그 URI로 리다이렉션 하도록 요청한다. 주로 POST 요청을 처리한 후, 클라이언트를 GET 메소드를 사용하여 다른 페이지로 리다이렉션하는 데 사용된다. 이는 POST 요청 결과를 새로 고침으로 인해 다시 제출되는 것을 방지하기 위해 사용된다.
POST 작업 시 303으로 리다이렉션을 하는 이유
사용자가 특정 페이지에서 새로 고침(F5 또는 브라우저 새로 고침 버튼 클릭)을 하면, 브라우저는 가장 최근의 요청을 반복적으로 실행하려고 하는데, 이는 "Form Resubmission"이라고 부르며, 이는 원치 않는 데이터 중복 제출로 이어질 수 있다. 이러한 브라우저의 행동은 웹 표준에 따른 것이며, 브라우저의 기본 동작이다. 마찬가지로 웹 사이트에서 POST 요청 시 클라이언트가 웹 페이지를 새로 고침하면서 해당 POST 요청이 다시 발송될 수 있는 것이다.
이 문제를 방지하기 위해 서버는 POST 요청 처리 후 클라이언트를 안전한 GET 요청으로 다른 페이지로 리다이렉트시키는 303 "See Other" 상태 코드를 사용한다. 이 방법은 POST/Redirect/GET (PRG) 패턴으로 알려져 있으며, 사용자가 데이터를 중복으로 제출하는 것을 방지하고, 서버 로드를 줄이며, 사용자 경험을 개선하는 데 도움을 준다.
이 리다이렉트를 수행하면, 사용자가 페이지를 새로 고침해도 POST 요청이 아닌 GET 요청이 발생하며, 불필요한 데이터 중복 전송을 방지할 수 있다.
서버 측 코드 (Node.js)
Node.js와 Express를 사용하여 303 리다이렉션을 구현하는 서버 코드 예시이다.
const express = require('express');
const app = express();
const port = 3000;
app.use(express.urlencoded({ extended: true })); // 양식 데이터를 파싱하기 위해 필요
// POST 요청을 받는 경로
app.post('/submit-form', (req, res) => {
// 양식 데이터 처리 로직 (예: 데이터베이스 저장)
console.log('Form data received:', req.body);
// GET 메소드를 사용하는 다른 페이지로 303 리다이렉션
res.redirect(303, '/thank-you');
});
// 감사 페이지
app.get('/thank-you', (req, res) => {
res.send('Thank you for submitting your form!');
});
app.listen(port, () => {
console.log(`Server running on <http://localhost>:${port}`);
});
클라이언트 측 코드 (HTML과 자바스크립트)
사용자가 양식을 제출하고 서버가 그 요청을 처리한 후 'Thank You' 페이지로 리다이렉션되는 과정을 보여주는 클라이언트 코드 예시이다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Submit Form</title>
</head>
<body>
<form action="<http://localhost:3000/submit-form>" method="POST">
<input type="text" name="username" placeholder="Enter your name" required>
<button type="submit">Submit</button>
</form>
</body>
</html>
이 HTML 양식은 사용자로부터 이름을 입력받아 서버로 POST 요청을 보낸다. 서버는 이 데이터를 받고 처리한 후, 사용자를 'Thank You' 페이지로 303 리다이렉션하여 중복 제출을 방지한다. 이러한 처리는 웹 애플리케이션에서 매우 흔하게 사용되며, 사용자의 실수로 인한 데이터 중복 입력을 효과적으로 방지한다.
2.4. 307 리다이렉션 (Temporary Redirect):
HTTP 상태 코드 307 "Temporary Redirect"는 클라이언트에게 요청된 리소스가 일시적으로 다른 URI에 있으며, 이후 요청에서도 원래의 HTTP 메소드를 변경하지 않고 그대로 사용해야 함을 알린다. 이는 302 상태 코드와 유사하지만, 307 리다이렉션은 명확하게 요청 메소드와 본문이 리다이렉션 후에도 변경되지 않아야 한다는 점에서 차이가 있다. 예를 들어, POST 요청이 307 리다이렉션을 받았다면, 리다이렉션 된 위치로의 후속 요청도 POST 메소드를 사용해야 한다.
상황의 이해
어떤 유저가 온라인 쇼핑몰에서 물건을 결제하는데, 그에 대한 결제 서버A에 유지보수 작업이 진행중일 수 있다. 그렇다면 결제 처리를 서버B에서 진행해야 할 것이다. 그런데, 이를 수행하기 위해서는 서버A가 자신에게 들어온 요청을 서버B로 이전할 수도 있지만, 이 경우 클라이언트 요청 속 메서드, 헤더, 바디가 그대로 유지되지 않을 수 있기 때문에, 요청을 이전처리 하는 것이 아닌 클라이언트가 서버B로 재요청 하게끔 해야 한다. 307 리다이렉션은 이렇게 클라이언트가 리소스의 위치를 주체적으로 인식하고 처리할 수 있게끔 하는 방식이다.
서버 측 코드 (Node.js)
Node.js와 Express를 사용하여 임시 리다이렉션을 처리하는 서버 코드이다. 이 예제에서는 클라이언트의 결제 정보 POST 요청을 받아들이고, 유지 보수 중인 메인 서버 대신 임시 결제 서버로 리다이렉션한다.
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json()); // JSON 본문을 파싱하기 위해 필요
// 메인 결제 경로
app.post('/main-payment', (req, res) => {
// 유지 보수 상태를 확인 (여기서는 항상 유지 보수 중이라고 가정)
const maintenance = true;
if (maintenance) {
// 유지 보수 중이므로 임시 결제 서버로 리다이렉션
res.redirect(307, '/temporary-payment');
} else {
// 결제 처리 로직 (여기서는 단순화를 위해 생략)
res.send('Payment processed successfully at main server');
}
});
// 임시 결제 경로
app.post('/temporary-payment', (req, res) => {
console.log('Received payment data:', req.body);
res.send('Payment processed successfully at temporary server');
});
app.listen(port, () => {
console.log(`Server running on <http://localhost>:${port}`);
});
클라이언트 측 코드 (HTML & JavaScript)
HTML 페이지와 JavaScript를 사용하여 결제 정보를 POST 요청으로 보내는 클라이언트 코드이다. 이 코드는 사용자가 결제 정보를 입력하고 제출 버튼을 클릭하면, 메인 결제 서버로 요청을 보낸다. 서버에서 307 리다이렉션 응답을 받으면, 클라이언트는 자동으로 임시 결제 서버로 요청을 재전송한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>307 Temporary Redirect Test</title>
</head>
<body>
<button id="sendData">Send POST Data</button>
<script>
document.getElementById('sendData').addEventListener('click', function() {
fetch('<http://localhost:3000/original>', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ message: 'Hello' })
})
.then(response => response.text())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
});
</script>
</body>
</html>
이 코드에서 fetch API는 redirect: 'follow' 옵션을 기본적으로 사용하므로, 서버로부터 307 리다이렉션 응답을 받으면 클라이언트는 지정된 새 위치로 요청을 자동으로 재전송한다. 결과적으로, 유지 보수 중인 서버가 리다이렉션을 통해 임시 서버로 요청을 유도하며, 클라이언트는 이 과정을 자연스럽게 경험하게 된다.
3. 각 HTTP 응답 상태 코드 유형 요약
301
"영구 이동"
처리 방식: 모든 후속 요청을 새 URL로 리다이렉션
예시 상황: old product page => new product page (새 상품 페이지로 이동)
302
"임시 이동"
처리 방식: 임시적으로 페이지를 다른 URL로 리다이렉션하며, 원래 URL로의 복귀 가능성 유지
예시 상황: product page => special offer page (기간 한정 세일 페이지로 이)
303
"양식 제출 후 이동"
처리 방식: POST 반복(Form Resubmission) 방지
예시 상황: 폼 제출 후, 서버가 처리 결과를 다른 페이지에서 보여주도록 하여 새로고침 시 POST가 재요청되는 것을 방지
307
"메서드 유지하며 임시 이동"
처리 방식: 후속 요청도 HTTP 메소드 유지 POST 처리
예시 상황: 서버가 유지보수 중이어서 다른 서버에서 요청을 처리해야 할 때, 재요청처리하여 POST 메소드 유지.
4. 결론
따라서, SEO 측면에서 서버 측에서 HTTP 리다이렉션을 처리하는 것이 일반적으로 더 바람직하다. 서버 측 리다이렉션은 검색 엔진이 쉽게 인식할 수 있으며, URL의 권한과 순위를 적절히 관리할 수 있도록 돕는다. 클라이언트 측에서 하드코딩으로 리다이렉션을 처리하는 것은 특정 상황에서만 사용되어야 하며, SEO에 중점을 둔다면 가능한 한 서버 측 리다이렉션을 사용하는 것이 좋다.
'컴퓨터 과학 > 기술용어' 카테고리의 다른 글
[IT기술] 웹 애플리케이션의 데이터 관리(1): 다양한 스토리지 솔루션 비교 (1) | 2024.05.10 |
---|---|
[IT기술] 웹소켓의 기본적인 이해와 활용방법 (1) | 2024.04.21 |