비틀리(Bitly)와 같은 URL 단축 서비스는 사용자가 긴 URL을 짧은 형태로 변환해주고, 그 짧은 URL을 통해 원래의 긴 URL로 리다이렉션 해주는 기능을 제공합니다. 비틀리와 같은 서비스를 구현하기 위해 필요한 기본적인 단계를 설명하겠습니다.
서비스 구현방법
1. 프로젝트 설정 언어 및 프레임워크 선택: Python (Flask, Django), JavaScript (Node.js, Express), Java (Spring Boot) 등. 데이터베이스 선택: MySQL, PostgreSQL, MongoDB 등.
2. 데이터 모델 설계 URL 모델: 원본 URL, 단축된 URL, 생성된 날짜, 클릭 수 등.
3. URL 단축 알고리즘 단축된 URL을 생성하기 위한 알고리즘이 필요합니다. 보통 Base62(숫자와 대문자/소문자 알파벳) 인코딩을 사용합니다.
4. 주요 기능 구현
URL 단축
사용자가 긴 URL을 제출하면, 데이터베이스에 저장.
URL의 고유 ID를 가져와 Base62로 인코딩하여 단축된 URL 생성.
단축된 URL을 사용자에게 반환.
import string
import random
BASE62 = string.ascii_letters + string.digits
def encode(num):
s = []
while num:
num, rem = divmod(num, 62)
s.append(BASE62[rem])
return ''.join(reversed(s))
URL 리다이렉션
사용자가 단축된 URL을 요청하면, 데이터베이스에서 해당 URL의 원본 URL을 검색.
원본 URL로 리다이렉션.
from flask import Flask, redirect
import sqlite3
app = Flask(__name__)
@app.route('/<short_url>')
def redirect_url(short_url):
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
cursor.execute("SELECT original_url FROM urls WHERE short_url = ?", (short_url,))
result = cursor.fetchone()
conn.close()
if result:
return redirect(result[0])
else:
return "URL not found", 404
5. 추가 기능 클릭 수 통계: URL이 몇 번 클릭되었는지 기록. 사용자 관리: 로그인 기능을 통해 사용자별 URL 관리. 만료 기간 설정: URL의 유효 기간을 설정.
6. 배포 서버 선택: AWS, Heroku, DigitalOcean 등. 도메인 설정: 짧은 도메인 이름 등록. 보안: HTTPS 적용, 데이터베이스 보안 설정.
예시: 전체 코드
from flask import Flask, request, redirect, jsonify
import sqlite3
import string
import random
app = Flask(__name__)
BASE62 = string.ascii_letters + string.digits
def encode(num):
s = []
while num:
num, rem = divmod(num, 62)
s.append(BASE62[rem])
return ''.join(reversed(s))
def create_table():
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
cursor.execute('''CREATE TABLE IF NOT EXISTS urls
(id INTEGER PRIMARY KEY, original_url TEXT, short_url TEXT, clicks INTEGER)''')
conn.commit()
conn.close()
create_table()
@app.route('/shorten', methods=['POST'])
def shorten_url():
original_url = request.json['url']
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
cursor.execute("INSERT INTO urls (original_url, clicks) VALUES (?, 0)", (original_url,))
conn.commit()
url_id = cursor.lastrowid
short_url = encode(url_id)
cursor.execute("UPDATE urls SET short_url = ? WHERE id = ?", (short_url, url_id))
conn.commit()
conn.close()
return jsonify({'short_url': short_url})
@app.route('/<short_url>')
def redirect_url(short_url):
conn = sqlite3.connect('database.db')
cursor = conn.cursor()
cursor.execute("SELECT original_url, clicks FROM urls WHERE short_url = ?", (short_url,))
result = cursor.fetchone()
if result:
cursor.execute("UPDATE urls SET clicks = ? WHERE short_url = ?", (result[1] + 1, short_url))
conn.commit()
conn.close()
return redirect(result[0])
else:
conn.close()
return "URL not found", 404
if __name__ == '__main__':
app.run(debug=True)
위 예제는 기본적인 URL 단축 및 리다이렉션 기능을 포함하고 있습니다. 이를 바탕으로 추가 기능을 구현하여 서비스를 확장할 수 있습니다.
데이터베이스 설정
비틀리와 같은 URL 단축 서비스를 구현할 때, 데이터베이스는 중요한 역할을 합니다. 여기서는 SQL 데이터베이스 (예: MySQL, PostgreSQL)와 NoSQL 데이터베이스 (예: MongoDB) 두 가지를 사용하는 방법을 설명하겠습니다. 1. SQL 데이터베이스 설정
1.1. 데이터베이스 테이블 설계 하나의 테이블을 사용하여 URL 정보를 저장할 수 있습니다. 테이블 스키마는 다음과 같습니다
CREATE TABLE urls (
id SERIAL PRIMARY KEY,
original_url TEXT NOT NULL,
short_url VARCHAR(10) UNIQUE NOT NULL,
clicks INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
1.2. Python과 SQL 데이터베이스 연동
Python의 SQLAlchemy와 같은 ORM(Object Relational Mapping)을 사용하면 데이터베이스와 쉽게 연동할 수 있습니다.
from flask import Flask, request, redirect, jsonify
from flask_sqlalchemy import SQLAlchemy
import string
import random
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://username:password@localhost/dbname'
db = SQLAlchemy(app)
BASE62 = string.ascii_letters + string.digits
class URL(db.Model):
id = db.Column(db.Integer, primary_key=True)
original_url = db.Column(db.Text, nullable=False)
short_url = db.Column(db.String(10), unique=True, nullable=False)
clicks = db.Column(db.Integer, default=0)
created_at = db.Column(db.DateTime, server_default=db.func.now())
def encode(num):
s = []
while num:
num, rem = divmod(num, 62)
s.append(BASE62[rem])
return ''.join(reversed(s))
@app.route('/shorten', methods=['POST'])
def shorten_url():
original_url = request.json['url']
url = URL(original_url=original_url, clicks=0)
db.session.add(url)
db.session.commit()
url.short_url = encode(url.id)
db.session.commit()
return jsonify({'short_url': url.short_url})
@app.route('/<short_url>')
def redirect_url(short_url):
url = URL.query.filter_by(short_url=short_url).first_or_404()
url.clicks += 1
db.session.commit()
return redirect(url.original_url)
if __name__ == '__main__':
app.run(debug=True)
2. NoSQL 데이터베이스 설정
2.1. 데이터베이스 컬렉션 설계
MongoDB를 사용한다면, URL 정보를 저장하기 위한 컬렉션을 설계할 수 있습니다. 문서 구조는 다음과 같습니다:
{
"_id": ObjectId,
"original_url": "http://example.com",
"short_url": "abc123",
"clicks": 0,
"created_at": ISODate("2024-05-23T00:00:00Z")
}
2.2. Python과 NoSQL 데이터베이스 연동
Python의 PyMongo를 사용하여 MongoDB와 연동할 수 있습니다.
from flask import Flask, request, redirect, jsonify
from pymongo import MongoClient
import string
import random
from datetime import datetime
app = Flask(__name__)
client = MongoClient('mongodb://localhost:27017/')
db = client['url_shortener']
urls = db['urls']
BASE62 = string.ascii_letters + string.digits
def encode(num):
s = []
while num:
num, rem = divmod(num, 62)
s.append(BASE62[rem])
return ''.join(reversed(s))
@app.route('/shorten', methods=['POST'])
def shorten_url():
original_url = request.json['url']
url_id = urls.insert_one({
"original_url": original_url,
"clicks": 0,
"created_at": datetime.utcnow()
}).inserted_id
short_url = encode(url_id.binary[0])
urls.update_one({'_id': url_id}, {'$set': {'short_url': short_url}})
return jsonify({'short_url': short_url})
@app.route('/<short_url>')
def redirect_url(short_url):
url = urls.find_one_and_update(
{'short_url': short_url},
{'$inc': {'clicks': 1}},
return_document=True
)
if url:
return redirect(url['original_url'])
else:
return "URL not found", 404
if __name__ == '__main__':
app.run(debug=True)