트위터, SMS 문자 메시지 및 기타 형태의 단문 메시지 상호 작용이 붐을 이루면서 URL 단축 서비스도 붐을 이뤘습니다. 예를 들어 TinyURL, Bitly, Owly 등을 사용할 수 있습니다. 이 서비스의 목적은 매우 긴 URL을 메시지로 배포하기 위해 훨씬 짧게 만드는 것입니다.
그렇다면 이러한 URL 단축 서비스는 어떻게 작동할까요?
나만의 URL 단축기를 만드는 방법을 알아보겠습니다. Node.js 사용 Express 프레임워크와 N1QL이 포함된 Couchbase 서버를 사용합니다. 이 예제에서는 Node.js를 사용하여 짧은 URL을 생성하고 Couchbase를 사용하여 저장 및 액세스합니다.
요구 사항
이 프로젝트를 가능하게 하기 위한 요구 사항은 그리 많지 않습니다. 성공하려면 최소한 다음이 필요합니다:
- 카우치베이스 서버 4.1+
- Node.js 4.0+
N1QL 쿼리를 지원하는 Couchbase Server 버전을 사용해야 합니다. Node.js 버전은 덜 엄격하지만 애플리케이션을 제공하고 Node 패키지 관리자(NPM)를 사용하여 종속성을 가져오는 데 필요합니다.
카우치베이스 준비 및 데이터 형식 이해하기
Node.js 애플리케이션 개발을 시작하기 전에 데이터 요금제를 이해하고 N1QL 쿼리를 허용하도록 Couchbase Server를 구성해야 합니다.
Couchbase에서는 다음 형식으로 데이터를 저장하는 것이 목표입니다:
|
1 2 3 4 5 |
{ "id": "5Qp8oLmWX", "longUrl": "https://www.thepolyglotdeveloper.com/2016/08/using-couchbase-server-golang-web-application/", "shortUrl": "http://localhost:3000/5Qp8oLmWX" } |
애플리케이션에 긴 URL을 전달하고 데이터 조각을 기반으로 고유한 짧은 해시를 생성합니다. 이 해시는 짧은 URL을 구성할 때 사용되며, 이는 Couchbase 문서에도 저장됩니다. 문서 자체의 ID도 해시 값의 ID가 됩니다.
이제 애플리케이션의 데이터를 저장하기 위한 Couchbase Server 버킷을 만들어야 합니다. 이 버킷은 Couchbase Server 관리 대시보드를 통해 만들 수 있습니다. 이 버킷을 다음과 같이 부르겠습니다. 예제.
데이터를 쿼리할 때 항상 ID 값을 기준으로 조회하는 것은 아닙니다. 즉, N1QL 쿼리를 허용하려면 문서 값에 대한 인덱스를 만들어야 합니다. 간단하게 하려면 다음과 같이 간단한 기본 인덱스를 만드세요:
|
1 |
만들기 기본 INDEX 켜기 `예제` 사용 GSI; |
이 쿼리는 Couchbase 서버 쿼리 워크벤치(엔터프라이즈 에디션) 또는 CBQ로 알려진 Couchbase 셸을 사용하여 실행할 수 있습니다. 이 인덱스는 매우 일반적이기 때문에 가장 빠르지는 않지만 매우 간단한 애플리케이션의 요구 사항을 충족할 것입니다.
Express 프레임워크로 Node.js URL 단축기 애플리케이션 개발하기
데이터베이스가 제대로 구성되면 애플리케이션 뒤에 있는 코드에 대해 걱정할 수 있습니다. 이 애플리케이션은 Express 프레임워크와 Couchbase에 크게 의존할 뿐만 아니라 해시드라고 하는 해싱 라이브러리에도 의존합니다.
종속성이 있는 프로젝트 만들기
명령 프롬프트(Windows) 또는 터미널(Mac 및 Linux)에서 새 Node.js 프로젝트를 만들어 보겠습니다:
|
1 |
npm init --y |
위의 명령은 package.json 파일은 현재 명령줄을 통해 이동한 위치에서 찾을 수 있습니다. 따라서 새 디렉토리에 있기를 바랍니다.
이제 프로젝트 종속성을 설치해야 합니다. 명령줄에서 다음을 실행합니다:
|
1 |
npm 설치 카우치베이스 body-파서 express 해시드 --저장 |
이 시점에서 자바스크립트 개발에 대해 걱정할 수 있습니다.
Node.js 애플리케이션 부트스트랩하기
이 프로젝트를 단순하고 이해하기 쉽게 유지하기 위해 모든 애플리케이션 로직을 단일 파일에 보관하겠습니다. 프로덕션 애플리케이션에서는 깔끔함과 유지보수성을 위해 분할하는 것이 좋겠지만 이 예제에서는 괜찮을 것입니다.
라는 파일을 만듭니다. app.js 파일을 프로젝트 디렉토리의 루트에 생성합니다. 이 파일에서 가장 먼저 할 일은 설치된 종속성을 다음과 같이 임포트하는 것입니다:
|
1 2 3 4 |
var 카우치베이스 = require("couchbase"); var Express = require("express"); var 바디파서 = require("body-parser"); var 해시드 = require("해시드"); |
아직 설명하지 않았기 때문에 본문 파서 종속성에 대해 지금 설명하겠습니다. 이 종속성을 통해 본문이 포함된 요청을 할 수 있습니다. 예를 들어, POST 또는 PUT 요청을 할 때 URL 매개변수나 쿼리 매개변수 대신 JSON 본문을 포함하는 것이 일반적입니다.
종속성을 가져온 후 Express 프레임워크와 Couchbase N1QL 엔진을 초기화해야 합니다:
|
1 2 |
var 앱 = Express(); var N1qlQuery = 카우치베이스.N1qlQuery; |
우리가 가져온 동안 본문 파서 플러그인을 아직 초기화하지 않았습니다. JSON 및 URL로 인코딩된 값을 허용하려면 다음과 같이 종속성을 구성해야 합니다:
|
1 2 |
앱.사용(바디파서.json()); 앱.사용(바디파서.urlencoded({ 확장: true })); |
이 시점에서 모든 종속성이 초기화됩니다. 이제 Couchbase Server 클러스터 및 애플리케이션 버킷에 대한 연결을 설정하는 것이 좋습니다. 이 작업은 다음 줄을 통해 수행할 수 있습니다:
|
1 |
var 버킷 = (new 카우치베이스.클러스터("couchbase://localhost")).오픈버킷("예제"); |
마지막으로 다음을 사용하여 Node.js 애플리케이션을 서비스해 보겠습니다:
|
1 2 3 |
var 서버 = 앱.듣기(3000, 함수() { 콘솔.로그("포트 %s에서 수신 중...", 서버.주소().포트); }); |
로직을 추가하지 않았다는 사실을 눈치채셨을 것입니다. 지금까지는 애플리케이션을 부트스트랩으로만 만들었기 때문에 그 말이 맞습니다.
URL 단축기 애플리케이션 로직 만들기
이제 몇 가지 RESTful API 엔드포인트를 만들려고 합니다. 다음과 같은 엔드포인트를 만들겠습니다:
|
1 2 3 |
/ /확장 /create |
그리고 root 엔드포인트는 짧은 URL 뒤에 가려진 긴 URL로 이동하는 데 사용됩니다. 그리고 /확장 엔드포인트는 짧은 URL을 가져와 탐색하지 않고 긴 URL을 표시하고 /생성 엔드포인트는 긴 URL을 가져와 데이터베이스에 짧은 URL을 생성합니다.
부터 시작하여 /생성 그리고 아마도 가장 복잡한 엔드포인트는 다음과 같습니다:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
앱.post("/create", 함수(req, res) { 만약(!req.body.longUrl) { 반환 res.상태(400).보내기({"status": "오류", "메시지": "긴 URL이 필요합니다."}); } 버킷.쿼리(N1qlQuery.fromString("SELECT `" + 버킷._name + "`.* FROM `" + 버킷._name + "` WHERE longUrl = $1"), [req.body.longUrl], 함수(오류, 결과) { 만약(오류) { 반환 res.상태(400).보내기(오류); } 만약(결과.길이 == 0) { var 해시드 = new 해시드(); var 응답 = { id: 해시드.encode((new 날짜).getTime()), longUrl: req.body.longUrl } 응답.shortUrl = "http://localhost:3000/" + 응답.id; 버킷.삽입(응답.id, 응답, 함수(오류, 결과) { 만약(오류) { 반환 res.상태(400).보내기(오류); } res.보내기(응답); }); } else { res.보내기(결과[0]); } }); }); |
이 엔드포인트는 JSON 본문을 기대하는 POST 요청입니다. 만약 longUrl JSON 속성이 존재하지 않으면 사용자에게 오류가 반환됩니다.
실제로 짧은 URL을 생성하기 전에 이미 생성된 URL이 없는지 확인해야 합니다. 긴 URL 하나당 짧은 URL 하나가 필요하기 때문입니다. 이를 위해 매개변수화된 N1QL 쿼리를 생성하면 됩니다. longUrl 속성을 확인합니다. 응답에 문서가 포함되어 있으면 문서가 이미 존재하므로 반환합니다. 응답에 문서가 없으면 문서를 만들어야 합니다.
사용 해시드 종속성을 사용하면 타임스탬프를 기반으로 해시를 생성하고 이를 아이디와 짧은 URL로 사용할 수 있습니다. 이 새 문서를 삽입한 후 사용자에게 다시 반환할 수 있습니다.
이제 이러한 짧은 URL을 확장하는 방법을 살펴보겠습니다.
|
1 2 3 4 5 6 7 8 9 10 11 |
앱.get("/확장", 함수(req, res) { 만약(!req.쿼리.shortUrl) { 반환 res.상태(400).보내기({"status": "오류", "메시지": "짧은 URL이 필요합니다."}); } 버킷.쿼리(N1qlQuery.fromString("SELECT `" + 버킷._name + "`.* FROM `" + 버킷._name + "` WHERE shortUrl = $1"), [req.쿼리.shortUrl], 함수(오류, 결과) { 만약(오류) { 반환 res.상태(400).보내기(오류); } res.보내기(결과.길이 > 0 ? 결과[0] : {}); }); }); |
위의 코드는 /생성 엔드포인트. 우리는 shortUrl 값을 설정하고 N1QL을 사용하여 쿼리합니다. 발견되면 긴 URL을 응답과 함께 반환할 수 있습니다.
마지막으로 탐색에 대해 걱정할 수 있습니다.
|
1 2 3 4 5 6 7 8 9 10 11 |
앱.get("/:id", 함수(req, res) { 만약(!req.매개변수.id) { 반환 res.상태(400).보내기({"status": "오류", "메시지": "아이디가 필요합니다"}); } 버킷.get(req.매개변수.id, 함수(오류, 결과) { 만약(오류) { 반환 res.상태(400).보내기(오류); } res.리디렉션(결과.값.longUrl); }) }); |
짧은 URL의 형식은 다음과 같습니다. http://localhost:3000/5Qp8oLmWX 로 이동하여 API 서비스와 동일한 위치에 있습니다. 이것이 의미하는 바는 5Qp8oLmWX 는 URL 매개 변수에 불과합니다. root 엔드포인트.
ID를 사용하면 키 값을 기반으로 문서 조회를 수행할 수 있습니다. 성공하면 현재 저장된 문서를 가져올 수 있습니다.
전체 애플리케이션 소스 코드
방금 만든 애플리케이션의 전체 소스 코드를 보고 싶으시다면 아래에서 확인할 수 있습니다.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
var 카우치베이스 = require("couchbase"); var Express = require("express"); var 바디파서 = require("body-parser"); var 해시드 = require("해시드"); var 앱 = Express(); var N1qlQuery = 카우치베이스.N1qlQuery; 앱.사용(바디파서.json()); 앱.사용(바디파서.urlencoded({ 확장: true })); var 버킷 = (new 카우치베이스.클러스터("couchbase://localhost")).오픈버킷("예제"); 앱.get("/확장", 함수(req, res) { 만약(!req.쿼리.shortUrl) { 반환 res.상태(400).보내기({"status": "오류", "메시지": "짧은 URL이 필요합니다."}); } 버킷.쿼리(N1qlQuery.fromString("SELECT `" + 버킷._name + "`.* FROM `" + 버킷._name + "` WHERE shortUrl = $1"), [req.쿼리.shortUrl], 함수(오류, 결과) { 만약(오류) { 반환 res.상태(400).보내기(오류); } res.보내기(결과.길이 > 0 ? 결과[0] : {}); }); }); 앱.post("/create", 함수(req, res) { 만약(!req.body.longUrl) { 반환 res.상태(400).보내기({"status": "오류", "메시지": "긴 URL이 필요합니다."}); } 버킷.쿼리(N1qlQuery.fromString("SELECT `" + 버킷._name + "`.* FROM `" + 버킷._name + "` WHERE longUrl = $1"), [req.body.longUrl], 함수(오류, 결과) { 만약(오류) { 반환 res.상태(400).보내기(오류); } 만약(결과.길이 == 0) { var 해시드 = new 해시드(); var 응답 = { id: 해시드.encode((new 날짜).getTime()), longUrl: req.body.longUrl } 응답.shortUrl = "http://localhost:3000/" + 응답.id; 버킷.삽입(응답.id, 응답, 함수(오류, 결과) { 만약(오류) { 반환 res.상태(400).보내기(오류); } res.보내기(응답); }); } else { res.보내기(결과[0]); } }); }); 앱.get("/:id", 함수(req, res) { 만약(!req.매개변수.id) { 반환 res.상태(400).보내기({"status": "오류", "메시지": "아이디가 필요합니다"}); } 버킷.get(req.매개변수.id, 함수(오류, 결과) { 만약(오류) { 반환 res.상태(400).보내기(오류); } res.리디렉션(결과.값.longUrl); }) }); var 서버 = 앱.듣기(3000, 함수() { 콘솔.로그("포트 %s에서 수신 중...", 서버.주소().포트); }); |
최적화할 수 있는 방법은 많겠지만, 저희는 성공적인 프로젝트를 만들기 위한 로직에 더 많은 신경을 썼습니다.
결론
방금 애플리케이션 로직으로 Node.js, NoSQL 데이터베이스로 Couchbase Server, 쿼리 기술로 N1QL을 사용하여 아주 기본적인 URL 단축기를 만드는 방법을 살펴보았습니다.
이를 한 단계 더 발전시키고 싶다면 분석 정보를 추적할 수 있습니다. 예를 들어, 누군가 다음 페이지로 이동하는 경우 root 엔드포인트, 카운터를 늘리거나 브라우저 에이전트를 저장하세요. URL 단축기 애플리케이션에 멋진 요소를 추가하는 간단한 방법.