Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Redis

Xây dựng một giải pháp thay thế LinkTree mã nguồn mở, miễn phí với Astro, Upstash và GitHub

Trong bài đăng này, tôi nói về cách itsmy.fyi (một nguồn mở thay thế cho LinkTree) được xây dựng với Upstash, Astro, GitHub và Edgio. Upstash đã giúp tôi quản lý dữ liệu (CRUD) của tất cả người dùng, đưa ra giới hạn tốc độ rất lớn so với API GitHub cho các hoạt động CRUD và triển khai giới hạn tốc độ chi tiết.

Xây dựng một giải pháp thay thế LinkTree mã nguồn mở, miễn phí với Astro, Upstash và GitHub

Những gì chúng tôi sẽ sử dụng

  • Astro (Front-end và Back-end)
  • Upstash (Giới hạn tốc độ và hoạt động CRUD)
  • Sự cố GitHub &Webhooks (CMS công khai để quản lý hồ sơ người dùng)
  • CSS Tailwind (Tạo kiểu)
  • Edgio (Triển khai)

Những gì bạn cần

  • Tài khoản GitHub
  • Tài khoản Upstash để tạo cơ sở dữ liệu

Thiết lập Upstash Redis

Khi bạn đã tạo tài khoản Upstash và đăng nhập, bạn sẽ chuyển tới tab Redis và tạo cơ sở dữ liệu.

Xây dựng một giải pháp thay thế LinkTree mã nguồn mở, miễn phí với Astro, Upstash và GitHub

Xây dựng một giải pháp thay thế LinkTree mã nguồn mở, miễn phí với Astro, Upstash và GitHub

Sau khi tạo cơ sở dữ liệu, bạn sẽ chuyển đến tab Chi tiết. Cuộn xuống cho đến khi bạn tìm thấy Connect your database phần. Sao chép nội dung và lưu ở nơi an toàn.

Xây dựng một giải pháp thay thế LinkTree mã nguồn mở, miễn phí với Astro, Upstash và GitHub

Ngoài ra, hãy cuộn xuống cho đến khi bạn tìm thấy phần REST API và chọn nút .env. Sao chép nội dung và lưu ở nơi an toàn.

Xây dựng một giải pháp thay thế LinkTree mã nguồn mở, miễn phí với Astro, Upstash và GitHub

Thiết lập dự án

Để thiết lập, chỉ cần sao chép kho lưu trữ ứng dụng và làm theo hướng dẫn này để tìm hiểu mọi thứ có trong đó. Để phân nhánh dự án, hãy chạy:

git clone https://github.com/rishi-raj-jain/itsmy.fyi
cd itsmy.fyi
yarn install

Khi bạn đã sao chép kho lưu trữ, bạn sẽ tạo một tệp .env. Bạn sẽ thêm các mục chúng tôi đã lưu từ các phần trên.

Nó sẽ trông giống như thế này:

.env
# Obtained from your GitHub repo
GITHUB_API_TOKEN="to_create_and_update_github_comments"
GITHUB_WEBHOOK_SECRET="if_you_are_matching_github_webhooks_sha256"
 
# Obtained from the steps as above
UPSTASH_DB="your_upstash_redis_from_above"
UPSTASH_REDIS_REST_URL="your_upstash_redis_rest__url_from_above"
UPSTASH_REDIS_REST_TOKEN="your_upstash_redis_rest__token_from_above"

Sau các bước này, bạn sẽ có thể khởi động môi trường cục bộ bằng lệnh sau:

yarn run edgio:dev

Cấu trúc kho lưu trữ

Đây là cấu trúc thư mục chính của dự án. Tôi đã khoanh tròn màu đỏ các tệp sẽ được thảo luận thêm trong bài đăng này liên quan đến Hoạt động CRUD, Giới hạn tốc độ và các tệp mà chúng được tham chiếu.

Xây dựng một giải pháp thay thế LinkTree mã nguồn mở, miễn phí với Astro, Upstash và GitHub

Luồng dữ liệu cấp cao

Đây là sơ đồ cấp cao về cách dữ liệu được truyền đi.

  • Nếu người dùng truy cập itsmy.fyi/me/slug và phản hồi cho trang này không được lưu vào bộ nhớ đệm (hoặc đang được xác thực lại), nó sẽ gọi hàm getUserInfo để truy xuất json của người dùng từ Upstash DB
  • Nếu người dùng tạo (các), cập nhật hoặc xóa (các) Sự cố GitHub, GitHub sẽ kích hoạt Webhook mà POST tới điểm cuối. Ở điểm cuối đó, Giới hạn tỷ lệ Upstash đầu tiên được sử dụng để đánh giá xem có thể thực hiện thay đổi được yêu cầu hay không, sau đó sử dụng Upstash, (các) json người dùng sẽ được tạo, cập nhật hoặc xóa.

Xây dựng một giải pháp thay thế LinkTree mã nguồn mở, miễn phí với Astro, Upstash và GitHub

(Các) Hồ sơ người dùng Hoạt động CRUD thông qua Upstash Redis

Trong phần này, chúng ta sẽ đi sâu vào cách thực hiện tìm nạp, cập nhật và xóa dữ liệu cho (các) hồ sơ người dùng. Chúng tôi sử dụng Upstash liên tục (thông qua ioredis ) để tìm nạp và hiển thị dữ liệu.

Tại sao tôi chuyển từ GitHub sang Upstash cho hoạt động CRUD?

Mặc dù tôi bắt đầu với GitHub làm nguồn quản lý dữ liệu:từ biểu mẫu dữ liệu Github Issues đến GitHub Webhooks đến json của người dùng CRUD trong kho lưu trữ, nhưng các hạn chế trên GitHub REST API:1,000 requests per hour per repository dường như đã hạn chế và làm thay đổi mục đích sử dụng nền tảng.

Upstash nổi bật hơn nhiều vì nó cung cấp cho tôi 10 nghìn lệnh hàng ngày trong gói miễn phí của họ ngay từ đầu và tỷ lệ rất tối thiểu sau đó khi mức sử dụng của tôi tăng lên. Cách tiếp cận này cho phép tôi thu hút được nhiều người dùng hơn với mức giá gần như không mất phí và lặp lại nhanh hơn mà không phải lo lắng về việc mở rộng quy mô và quản lý chi phí của cơ sở dữ liệu.

getUserInfo:Đang tìm nạp chức năng hồ sơ người dùng

getUserInfo hàm sử dụng hget của ioredis thông qua slug làm chìa khóa để thực hiện yêu cầu API tới Upstash cho trang hồ sơ người dùng có liên quan, được xác định bằng slug duy nhất .Nếu hồ sơ người dùng đó không có mặt (hoặc có lỗi), hàm sẽ được đặt để trả về một đối tượng có { code: 0 } để sau đó người dùng có thể được tự động chuyển hướng đến 404 theo lộ trình động của Astro.

// File: lib/Upstash/users/get.js
// Read User Profile Code
 
import redis from "../setup";
 
export async function getUserInfo(slug) {
 try {
 const userData = await redis.hget("profiles", slug);
 const parsedData = JSON.parse(userData);
 if (parsedData.slug === slug) {
 return { ...parsedData, code: 1 };
 }
 return {
 code: 0,
 error: `slug doesn't match for the user.`,
 };
 } catch (e) {
 const error = e.message || e.toString();
 console.log(error);
 return {
 code: 0,
 error,
 };
 }
}

Tương tự các thao tác CRUD còn lại như sau:

import redis from "../setup";
 
// File: @/lib/Upstash/users/delete.js
// Delete User Profile Code
export async function deleteUserInfo(slug) {
 try {
 await redis.hdel("profiles", slug);
 return { code: 1 };
 } catch (e) {
 console.log(e.message || e.toString());
 return {
 code: 0,
 };
 }
}
 
// File: @/lib/Upstash/users/post.js
// Create/Update User Profile Code
export async function postUserInfo(data) {
 try {
 await redis.hset("profiles", data.slug, JSON.stringify(data));
 return { code: 1 };
 } catch (e) {
 const error = e.message || e.toString();
 console.log(error);
 return {
 code: 0,
 error,
 };
 }
}

Giới hạn tỷ lệ

Để triển khai giới hạn tốc độ trong môi trường không có máy chủ với Edgio, chúng tôi sử dụng ứng dụng khách cơ sở dữ liệu Upstash Redis và thư viện giới hạn tốc độ có tên @upstash/ratelimit .

@/lib/Upstash/ratelimit.js
// Reference Function to ratelimiting
 
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
 
import { getENV } from "@/lib/env";
 
const url = getENV("UPSTASH_REDIS_REST_URL");
const token = getENV("UPSTASH_REDIS_REST_TOKEN");
 
export const ratelimit = (number, time) => {
 if (url && token) {
 return new Ratelimit({
 redis: new Redis({
 url,
 token,
 }),
 limiter: Ratelimit.fixedWindow(number, time),
 });
 }
 return;
};

Bằng cách sử dụng Giới hạn tỷ lệ, tôi đã có thể đạt được những điều sau:

A. Tận dụng dịch vụ - hoàn toàn miễn phí &không giới hạn

Bằng cách sử dụng Giới hạn tỷ lệ, tôi có thể công khai API tạo hồ sơ! Điều này cho phép tôi thể hiện những lợi ích của hệ thống, tức là dễ dàng thiết lập hồ sơ qua GUI. Theo nghĩa đen, bất kỳ ai cũng có thể tạo 3 hồ sơ trong một tuần thông qua chính trang web (itsmy.fyi) và để có quyền truy cập không giới hạn vào các tính năng như chỉnh sửa hồ sơ, tạo hồ sơ không giới hạn, người dùng phải chuyển sang cách tạo hồ sơ GitHub. Chúng tôi có thể thực thi giới hạn tốc độ của 3 hồ sơ trong một tuần dựa trên địa chỉ IP làm khóa.

// Rate limit 3 profiles in a week via the web for a user
const ratelimitUser = ratelimit(3, 7 * 24 * 60 * 60 + " s");
 
if (rateLimiter) {
 // Look at the x-0-client-ip set by Edgio in serverless
 const result = await rateLimiter.limit("x-0-client-ip");
 limit = result.limit;
 remaining = result.remaining;
 if (!result.success) {
 // Return a message
 }
}

B. Triển khai kiểm duyệt chi tiết đối với số lần chỉnh sửa của người dùng

Ngoài ra, thông qua Giới hạn tỷ lệ, chúng tôi có thể kiểm duyệt số lượng chỉnh sửa do người dùng thực hiện trong một phút dựa trên tên người dùng GitHub của họ. Hiện tại, chúng tôi cho phép họ thực hiện tối đa 3 thay đổi trong vòng một phút. Điều này sẽ giúp giảm mọi thư rác không thể nhìn thấy.

@/pages/github/hook/issue.js
const rateLimiter = ratelimit(3, "60 s");
 
if (rateLimiter) {
 const result = await rateLimiter.limit(context.sender.login);
 limit = result.limit;
 remaining = result.remaining;
 if (!result.success) {
 return {
 headers: {
 "X-RateLimit-Limit": limit,
 "X-RateLimit-Remaining": remaining,
 },
 body: JSON.stringify({
 message:
 "Too many updates in 1 minute. Please try again in a few minutes.",
 }),
 };
 }
}

Triển khai xác nhận cũ trong khi xác nhận lại ở rìa cho tất cả hồ sơ người dùng

Đoạn mã sau mô tả cách sử dụng khái niệmCũ trong khi xác nhận lại để cải thiện tỷ lệ nhấn bộ đệm. Trong mã (trong routes.js ), router.match Hàm được sử dụng để khớp tất cả hồ sơ người dùng (bắt đầu bằng /me/ ).Bên trong phương thức bộ đệm, chúng tôi ngăn chặn việc lưu trang vào bộ nhớ đệm trong trình duyệt và chỉ bật bộ đệm ẩn cạnh để luôn phục vụ người dùng nhanh chóng và có nội dung mới nhất. Tùy chọn cạnh được đặt thành maxAgeSeconds: 1 để đảm bảo dữ liệu được lưu vào bộ nhớ đệm chỉ trong một giây. staleWhileRevalidateSeconds tùy chọn được đặt là một năm để cho phép dữ liệu được cung cấp trực tiếp từ bộ đệm trong khi bộ đệm đang được làm mới.

tuyến đường.js
// User path(s)
router.match("/me/:path", ({ cache, removeUpstreamResponseHeader }) => {
 // Remove the cache-control header from Astro's standalone server
 removeUpstreamResponseHeader("cache-control");
 // Disable in browser caching, and use Edgio's edge to use SWR
 cache({
 edge: {
 maxAgeSeconds: 1,
 staleWhileRevalidateSeconds: 60 * 60 * 24 * 365,
 },
 browser: false,
 });
});

Việc sử dụng Stale While Revalidate có thể giúp cải thiện hiệu suất của ứng dụng bằng cách giảm tải trên máy chủ và cung cấp phản hồi nhanh hơn cho người dùng.

Tạo hồ sơ người dùng động một cách nhanh chóng

Astro giúp việc thiết lập các tuyến đường động trở nên cực kỳ dễ dàng. Trong ứng dụng, bạn sẽ tìm thấy src/pages/me/[slug].astro , ánh xạ các trang bắt đầu bằng /me/ .Ví dụ bao gồm /me/rishi-raj-jain/me/some-other-user .

Đang tìm nạp hồ sơ người dùng

Chúng tôi tìm nạp dữ liệu cho người dùng hiện tại bằng cách sử dụng slug tham số truy vấn được trích xuất từ các thông số Astro và gọi hàm getUserInfo (như được mô tả ở trên) để lấy tất cả dữ liệu người dùng liên quan. Trong trường hợp không tìm thấy hoặc có lỗi, chúng tôi sẽ chuyển hướng khách truy cập đến trang 404.

src/pages/me/[slug].astro
import { getUserInfo } from "@/lib/Upstash/users";
 
// Extract slug query
const { slug } = Astro.params;
 
// Get data from Upstash using the getUserInfo function
const {
 name: userName,
 image: userImage,
 links = [],
 socials = [],
 about = "",
 og = {},
 background = {},
 code = 1,
} = await getUserInfo(userSlug);
 
// In case the code: 0 is recevied, redirect to a 404
if (code === 0) {
 return Astro.redirect("/404");
}

Triển khai từ CLI

Bạn có thể tạo bản dựng chính thức cho ứng dụng của mình và thử nghiệm ứng dụng đó cục bộ bằng cách sử dụng:

yarn run edgio:build && yarn run edgio:production

Việc triển khai cần có tài khoản trên Eggio. Đăng ký miễn phí tại đây. Sau khi có tài khoản, bạn có thể triển khai lên Edgio bằng cách chạy lệnh sau trong thư mục gốc của dự án:

yarn run edgio:deploy

Bây giờ chúng ta đã hoàn tất việc triển khai! Vâng, chỉ vậy thôi.

Kết luận

Tóm lại, dự án này đã cung cấp kinh nghiệm quý báu trong việc triển khai giới hạn tốc độ chi tiết, hoạt động dữ liệu CRUD trong serverless, sử dụng các sự cố GitHub làm CMS và đưa ra quyết định tốt hơn khi gửi MVP bằng cách sử dụng dịch vụ phù hợp với nhu cầu của bạn, tức là Upstash.