Helpex - Trao đổi & giúp đỡ Đăng nhập

Tạo trình rút ngắn URL với Node.js và Couchbase bằng N1QL

Với sự bùng nổ của Twitter, tin nhắn văn bản SMS và các hình thức tương tác tin nhắn ngắn khác, đã có sự bùng nổ về dịch vụ rút ngắn URL. Ví dụ: bạn có thể sử dụng TinyURL, Bitly, Owly, v.v. Mục đích ở đây là lấy các URL rất dài và làm cho chúng ngắn hơn đáng kể để phân phối trong một tin nhắn.

Nhưng các dịch vụ rút ngắn URL này hoạt động như thế nào?

Chúng ta sẽ xem cách tạo trình rút ngắn URL của riêng mình bằng Node.js với Express Framework và Couchbase Server với N1QL. Trong ví dụ của chúng tôi, các URL ngắn sẽ được tạo bằng Node.js và chúng sẽ được lưu trữ và truy cập bằng Couchbase.

Các yêu cầu

Không có quá nhiều yêu cầu để thực hiện dự án này. Tối thiểu bạn sẽ cần những điều sau để thành công:

  • Máy chủ Couchbase 4.1+
  • Node.js 4.0+

Chúng tôi cần sử dụng phiên bản Couchbase Server hỗ trợ các truy vấn N1QL. Phiên bản Node.js ít nghiêm ngặt hơn, nhưng chúng tôi sẽ cần nó để phục vụ ứng dụng của mình và lấy các phụ thuộc bằng cách sử dụng Trình quản lý gói Node (NPM).

Chuẩn bị Couchbase và Hiểu Định dạng Dữ liệu

Trước khi có thể bắt đầu phát triển ứng dụng Node.js của mình, chúng ta cần hiểu gói dữ liệu cũng như cấu hình Máy chủ Couchbase để cho phép các truy vấn N1QL.

Trong Couchbase, mục tiêu là lưu trữ dữ liệu của chúng tôi ở định dạng sau:

{
    "id": "5Qp8oLmWX",
    "longUrl": "https://www.thepolyglotdeveloper.com/2016/08/using-couchbase-server-golang-web-application/",
    "shortUrl": "http://localhost:3000/5Qp8oLmWX"
}

Chúng tôi sẽ chuyển cho ứng dụng một URL dài và tạo một băm ngắn duy nhất dựa trên một phần dữ liệu. Hàm băm này sẽ được sử dụng khi xây dựng URL ngắn cũng sẽ được lưu trữ trong tài liệu Couchbase. Bản thân id của tài liệu cũng sẽ là id của giá trị băm.

Bây giờ chúng ta cần tạo một thùng máy chủ Couchbase để lưu trữ dữ liệu cho ứng dụng của chúng ta. Nhóm này có thể được tạo thông qua Bảng điều khiển quản trị máy chủ Couchbase. Hãy gọi đây là ví dụ xô .

Khi truy vấn dữ liệu, chúng tôi sẽ không phải lúc nào cũng thực hiện tra cứu dựa trên giá trị id. Điều này có nghĩa là chúng ta sẽ cần tạo các chỉ mục trên các giá trị tài liệu để cho phép các truy vấn N1QL. Để đơn giản hóa mọi thứ, hãy tạo một chỉ mục chính đơn giản như sau:

CREATE PRIMARY INDEX ON `example` USING GSI;

Truy vấn này có thể được thực thi bằng Bàn làm việc Truy vấn Máy chủ Couchbase (Phiên bản Doanh nghiệp) hoặc Couchbase Shell được gọi là CBQ. Chỉ mục sẽ không nhanh nhất vì nó quá chung chung, nhưng nó sẽ đáp ứng các nhu cầu của ứng dụng rất đơn giản của chúng ta.

Phát triển ứng dụng Node.js URL Shortener với Express Framework

Với cơ sở dữ liệu được cấu hình đúng cách, chúng ta có thể lo lắng về mã đằng sau ứng dụng. Ứng dụng này sẽ phụ thuộc nhiều vào Express Framework và Couchbase, nhưng cũng có một thư viện băm được gọi là Hashids.

Tạo dự án với các phụ thuộc

Hãy tạo một dự án Node.js mới từ Command Prompt (Windows) hoặc Terminal (Mac và Linux):

npm init --y

Lệnh trên sẽ tạo tệp package.json ở bất kỳ nơi nào bạn hiện đang điều hướng đến thông qua dòng lệnh của mình. Vì vậy, hy vọng bạn đang ở trong một thư mục mới.

Bây giờ chúng ta cần cài đặt các phụ thuộc của dự án. Thực thi những điều sau từ dòng lệnh:

npm install couchbase body-parser express hashids --save

Tại thời điểm này, chúng ta có thể lo lắng về sự phát triển JavaScript.

Khởi động ứng dụng Node.js

Ngoài ra, hãy giữ cho dự án này đơn giản và dễ hiểu, chúng tôi sẽ giữ tất cả logic của ứng dụng trong một tệp duy nhất. Trong một ứng dụng sản xuất, có thể bạn sẽ muốn chia nhỏ nó để đảm bảo tính sạch sẽ và khả năng bảo trì, nhưng đối với ví dụ này, chúng ta sẽ ổn.

Tạo một tệp có tên app.js ở thư mục gốc của thư mục dự án của bạn. Trong tệp này, điều đầu tiên chúng ta sẽ làm là nhập các phần phụ thuộc đã cài đặt như sau:

var Couchbase = require("couchbase");
var Express = require("express");
var BodyParser = require("body-parser");
var Hashids = require("hashids");

Bởi vì tôi vẫn chưa giải thích sự body-parserphụ thuộc, tôi sẽ giải thích nó ngay bây giờ. Sự phụ thuộc này cho phép chúng tôi thực hiện các yêu cầu chứa một phần thân. Ví dụ: khi thực hiện các yêu cầu POST hoặc PUT, thông thường sẽ bao gồm nội dung JSON chứ không phải tham số URL hoặc tham số truy vấn.

Với các phụ thuộc được nhập, chúng ta cần khởi chạy Express Framework và Couchbase N1QL Engine:

var app = Express();
var N1qlQuery = Couchbase.N1qlQuery;

Trong khi chúng tôi đã nhập body-parserplugin, chúng tôi vẫn chưa khởi chạy nó. Chúng tôi muốn có thể chấp nhận các giá trị được mã hóa JSON và URL, vì vậy chúng tôi cần định cấu hình phần phụ thuộc như sau:

app.use(BodyParser.json());
app.use(BodyParser.urlencoded({ extended: true }));

Tại thời điểm này, tất cả các phụ thuộc của chúng ta đều được khởi tạo. Bây giờ sẽ là một ý tưởng hay để thiết lập kết nối với cụm máy chủ Couchbase và nhóm ứng dụng của chúng tôi. Điều này có thể được thực hiện với dòng sau:

var bucket = (new Couchbase.Cluster("couchbase://localhost")).openBucket("example");

Cuối cùng, hãy bắt đầu phục vụ ứng dụng Node.js của chúng tôi với những điều sau:

var server = app.listen(3000, function() {
    console.log("Listening on port %s...", server.address().port);
});

Bạn có thể nhận ra rằng chúng tôi chưa thực sự thêm bất kỳ logic nào. Bạn nhận ra điều đó đúng vì chúng tôi chỉ mới thực sự khởi động ứng dụng của mình cho đến nay.

Tạo logic ứng dụng rút gọn URL

Những gì chúng tôi muốn làm bây giờ là tạo một số điểm cuối API RESTful. Chúng tôi sẽ tạo các điểm cuối sau:

/
/expand
/create

Điểm cuối gốc sẽ được sử dụng để điều hướng đến một URL dài bị che khuất sau một URL ngắn. Điểm cuối / expand sẽ lấy một URL ngắn và hiển thị URL dài mà không cần điều hướng đến nó và điểm cuối / create sẽ lấy một URL dài và tạo một URL ngắn trong cơ sở dữ liệu.

Bắt đầu với điểm cuối / create và có lẽ là phức tạp nhất, chúng ta có những thứ sau:

app.post("/create", function(req, res) {
    if(!req.body.longUrl) {
        return res.status(400).send({"status": "error", "message": "A long URL is required"});
    }
    bucket.query(N1qlQuery.fromString("SELECT `" + bucket._name + "`.* FROM `" + bucket._name + "` WHERE longUrl = $1"), [req.body.longUrl], function(error, result) {
        if(error) {
            return res.status(400).send(error);
        }
        if(result.length == 0) {
            var hashids = new Hashids();
            var response = {
                id: hashids.encode((new Date).getTime()),
                longUrl: req.body.longUrl
            }
            response.shortUrl = "http://localhost:3000/" + response.id;
            bucket.insert(response.id, response, function(error, result) {
                if(error) {
                    return res.status(400).send(error);
                }
                res.send(response);
            });
        } else {
            res.send(result[0]);
        }
    });
});

Điểm cuối này là một yêu cầu POST yêu cầu một phần thân JSON. Nếu thuộc tính longUrlJSON không tồn tại, lỗi sẽ được trả lại cho người dùng.

Trước khi thực sự tạo URL ngắn, chúng tôi muốn đảm bảo rằng một URL chưa được tạo. Chúng tôi làm điều này vì chúng tôi muốn có một URL ngắn cho mỗi URL dài. Chúng ta có thể thực hiện điều này bằng cách tạo một truy vấn N1QL được tham số hóa dựa trên thuộc longUrltính. Nếu phản hồi chứa tài liệu, chúng tôi sẽ trả lại vì tài liệu đó đã tồn tại. Nếu phản hồi không có tài liệu, chúng ta cần tạo một tài liệu.

Sử dụng phần hashidsphụ thuộc, chúng tôi có thể tạo một băm dựa trên dấu thời gian và sử dụng nó làm id và URL ngắn của chúng tôi. Sau khi chèn tài liệu mới này, chúng tôi có thể trả lại cho người dùng.

Bây giờ chúng ta hãy xem cách mở rộng các URL ngắn đó.

app.get("/expand", function(req, res) {
    if(!req.query.shortUrl) {
        return res.status(400).send({"status": "error", "message": "A short URL is required"});
    }
    bucket.query(N1qlQuery.fromString("SELECT `" + bucket._name + "`.* FROM `" + bucket._name + "` WHERE shortUrl = $1"), [req.query.shortUrl], function(error, result) {
        if(error) {
            return res.status(400).send(error);
        }
        res.send(result.length > 0 ? result[0] : {});
    });
});

Đoạn mã trên sử dụng một khái niệm tương tự như điểm cuối / tạo . Chúng tôi lấy một shortUrlgiá trị và truy vấn nó bằng N1QL. Nếu được tìm thấy, chúng tôi có thể trả về URL dài kèm theo phản hồi.

Cuối cùng chúng ta có thể lo lắng về điều hướng.

app.get("/:id", function(req, res) {
    if(!req.params.id) {
        return res.status(400).send({"status": "error", "message": "An id is required"});
    }
    bucket.get(req.params.id, function(error, result) {
        if(error) {
            return res.status(400).send(error);
        }
        res.redirect(result.value.longUrl);
    })
});

Hãy nhớ rằng, các URL ngắn của chúng tôi có định dạng http: // localhost: 3000 / 5Qp8oLmWX , cùng vị trí với dịch vụ API của chúng tôi. Điều này có nghĩa là 5Qp8oLmWX chỉ là một tham số URL cho điểm cuối gốc của chúng tôi .

Với id, chúng ta có thể thực hiện tra cứu tài liệu dựa trên giá trị khóa. Nếu thành công, chúng tôi sẽ có tài liệu hiện đang được lưu trữ.

Mã nguồn ứng dụng đầy đủ

Trong trường hợp bạn muốn xem toàn bộ mã nguồn của ứng dụng chúng tôi vừa tạo, bạn có thể tìm thấy mã nguồn bên dưới.

var Couchbase = require("couchbase");
var Express = require("express");
var BodyParser = require("body-parser");
var Hashids = require("hashids");

var app = Express();
var N1qlQuery = Couchbase.N1qlQuery;

app.use(BodyParser.json());
app.use(BodyParser.urlencoded({ extended: true }));

var bucket = (new Couchbase.Cluster("couchbase://localhost")).openBucket("example");

app.get("/expand", function(req, res) {
    if(!req.query.shortUrl) {
        return res.status(400).send({"status": "error", "message": "A short URL is required"});
    }
    bucket.query(N1qlQuery.fromString("SELECT `" + bucket._name + "`.* FROM `" + bucket._name + "` WHERE shortUrl = $1"), [req.query.shortUrl], function(error, result) {
        if(error) {
            return res.status(400).send(error);
        }
        res.send(result.length > 0 ? result[0] : {});
    });
});

app.post("/create", function(req, res) {
    if(!req.body.longUrl) {
        return res.status(400).send({"status": "error", "message": "A long URL is required"});
    }
    bucket.query(N1qlQuery.fromString("SELECT `" + bucket._name + "`.* FROM `" + bucket._name + "` WHERE longUrl = $1"), [req.body.longUrl], function(error, result) {
        if(error) {
            return res.status(400).send(error);
        }
        if(result.length == 0) {
            var hashids = new Hashids();
            var response = {
                id: hashids.encode((new Date).getTime()),
                longUrl: req.body.longUrl
            }
            response.shortUrl = "http://localhost:3000/" + response.id;
            bucket.insert(response.id, response, function(error, result) {
                if(error) {
                    return res.status(400).send(error);
                }
                res.send(response);
            });
        } else {
            res.send(result[0]);
        }
    });
});

app.get("/:id", function(req, res) {
    if(!req.params.id) {
        return res.status(400).send({"status": "error", "message": "An id is required"});
    }
    bucket.get(req.params.id, function(error, result) {
        if(error) {
            return res.status(400).send(error);
        }
        res.redirect(result.value.longUrl);
    })
});

var server = app.listen(3000, function() {
    console.log("Listening on port %s...", server.address().port);
});

Có thể có nhiều cách tối ưu hóa có thể được thực hiện, nhưng chúng tôi quan tâm nhiều hơn đến tính logic trong việc biến dự án này thành một dự án thành công.

Phần kết luận

Bạn vừa thấy cách tạo một trình rút gọn URL rất cơ bản bằng cách sử dụng Node.js cho logic ứng dụng, Couchbase Server làm cơ sở dữ liệu NoSQL và N1QL làm công nghệ truy vấn.

Nếu bạn muốn đưa điều này lên cấp độ tiếp theo, bạn có thể theo dõi thông tin phân tích. Ví dụ: nếu ai đó điều hướng đến điểm cuối gốc , hãy tăng bộ đếm hoặc lưu trữ tác nhân trình duyệt. Những điều đơn giản để thêm một yếu tố thú vị vào ứng dụng trình rút gọn URL.

17 hữu ích 0 bình luận 8.2k xem chia sẻ

Có thể bạn quan tâm

loading