10 分钟内使用 Next.js 和 MongoDB 创建您自己的 URL 缩短器

2025-06-08

10 分钟内使用 Next.js 和 MongoDB 创建您自己的 URL 缩短器

动机

几周前,我正在开发一个 Twitter 机器人来发布我的热门文章,我发现有些文章的链接在推文中解析得不太好。不过,使用Rebrandly缩短了链接长度,效果很好。

所以,我决定为自己制作一个 URL 缩短器。


分解

我们需要一个

  • 为每个长 URL 创建唯一哈希的服务
  • 数据库保留长到短 URL 映射
  • 将短链接重定向到其目的地的服务

与往常一样,Next.js是我构建完整服务的首选,而MongoDB则是存储链接的首选。


发展

现在我们已经弄清楚了步骤,让我们一步一步来

设置项目

让我们使用该npx create-next-app url-shortener命令为我们的应用程序生成样板。

./.env.local

DB_NAME=url-shortner
ATLAS_URI_PROD=mongodb+srv://<user>:<password><cluster>.mongodb.net/url-shortner?retryWrites=true&w=majority

API_KEY=<a-long-random-string>
HOST=http://localhost:3000
Enter fullscreen mode Exit fullscreen mode

这些环境变量也应该存储在您的 Vercel 项目中。

托管此项目时,应将的值HOST设置为您的域名。如果您没有公共域名,则只需使用NEXT_PUBLIC_VERCEL_URL环境变量而不是HOST

设置 MongoDB

  1. 跑步npm i --save mongodb
  2. mongodb.ts在 repo 的根目录创建一个文件。
// ./mongodb.ts

import { Db, MongoClient } from "mongodb";
import { formatLog } from "./utils";

// Create cached connection variable
let cachedDB: Db | null = null;

// A function for connecting to MongoDB,
export default async function connectToDatabase(): Promise<Db> {
  // If the database connection is cached, use it instead of creating a new connection
  if (cachedDB) {
    console.info(formatLog("Using cached client!"));
    return cachedDB;
  }
  const opts = {
    useNewUrlParser: true,
    useUnifiedTopology: true,
  };
  console.info(formatLog("No client found! Creating a new one."));
  // If no connection is cached, create a new one
  const client = new MongoClient(process.env.ATLAS_URI_PROD as string, opts);
  await client.connect();
  const db: Db = client.db(process.env.DB_NAME);
  cachedDB = db;
  return cachedDB;
}

Enter fullscreen mode Exit fullscreen mode

添加创建短链接服务

继续添加一个./api/create-link.ts文件来为该服务创建 REST 端点。

我们需要注意以下几点

  1. 创建短 URL 需要唯一的哈希值。我以前nanoid会为长 URL 生成一个随机的短哈希值。
  2. 此端点只能通过 POST 方法访问。
  3. 我们应该设置 API-KEY 身份验证来保护端点。这可以通过生成一个长字符串并将其用作 API-KEY 标头来实现。
// ./api/create-link.ts

import { NextApiRequest, NextApiResponse } from "next";
import connectToDatabase from "../../mongodb";
import { customAlphabet } from "nanoid";
import { COLLECTION_NAMES } from "../../types";

const characters =
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const getHash = customAlphabet(characters, 4);

export default async function CreateLink(
  request: NextApiRequest,
  response: NextApiResponse
) {
  const apiKey = request.headers["api-key"] as string;
  if (request.method !== "POST" || apiKey !== process.env.API_KEY) {
    return response.status(405).json({
      type: "Error",
      code: 405,
      message: "Only POST method is accepted on this route",
    });
  }
  const { link } = request.body;

  if (!link) {
    response.status(400).send({
      type: "Error",
      code: 400,
      message: "Expected {link: string}",
    });
    return;
  }
  try {
    const database = await connectToDatabase();
    const urlInfoCollection = database.collection(COLLECTION_NAMES["url-info"]);
    const hash = getHash();
    const linkExists = await urlInfoCollection.findOne({
      link,
    });
    const shortUrl = `${process.env.HOST}/${hash}`;
    if (!linkExists) {
      await urlInfoCollection.insertOne({
        link,
        uid: hash,
        shortUrl: shortUrl,
        createdAt: new Date(),
      });
    }
    response.status(201);
    response.send({
      type: "success",
      code: 201,
      data: {
        shortUrl: linkExists?.shortUrl || shortUrl,
        link,
      },
    });
  } catch (e: any) {
    response.status(500);
    response.send({
      code: 500,
      type: "error",
      message: e.message,
    });
  }
}

Enter fullscreen mode Exit fullscreen mode

将短链接重定向到目标

现在我们可以创建短链接,让我们添加逻辑以将用户重定向到实际目的地。

为此,我们可以在 Next.js 应用程序中创建动态路由并在服务器端编写重定向逻辑。

// ./pages/[hash].tsx

import { NextApiRequest, NextApiResponse, NextPage } from "next";
import Head from "next/head";
import connectToDatabase from "../mongodb";
import { COLLECTION_NAMES } from "../types";

export async function getServerSideProps(request: NextApiRequest) {
  const hash = request.query.hash as string;
  const database = await connectToDatabase();
  const campaign = await database
    .collection(COLLECTION_NAMES["url-info"])
    .findOne({ uid: hash });

  if (campaign) {
    return {
      redirect: {
        destination: campaign.link,
        permanent: false,
      },
    };
  }

  return {
    props: {},
  };
}

const HashPage: NextPage = () => {
  return (
    <div>
      <Head>
        <title>URL Shortener</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <h1>Requested link not found</h1>
    </div>
  );
};

export default HashPage;

Enter fullscreen mode Exit fullscreen mode

hash如果数据库中有该值,则此页面将把用户重定向到目的地,否则将显示“未找到链接”消息。


托管

托管这个项目非常简单,因为 Next.js 与 Vercel 的集成非常出色。

简化的步骤列表:

  1. 将 Next.js 项目推送到 GitHub 存储库
  2. 前往https://vercel.app并使用您的 GitHub 帐户登录
  3. url-shortener通过单击 Vercel 仪表板上的“新建项目”按钮来导入存储库。

您还可以在此处阅读有关此内容的详细信息

完成上述步骤后,前往项目设置并将我们在.env.local文件中定义的环境变量添加到 Vercel 项目的环境变量中。

您还可以从设置中将自定义域连接到此项目。

🎉 太棒了!您的 URL 缩短器已准备就绪并托管。


下一步是什么?

好吧,您可以像我一样继续将此项目用作 REST API,或者您可以创建一个前端以使其成为 Web 应用程序。

在将其作为公共网络应用程序之前,请确保采取额外的安全措施。


您可以从此GitHub Repo克隆此项目。


本文不适用于生产,仅供学习之用。

上述方法可以进行许多优化,例如使用更好的数据库或正确索引以加快速度。

希望这篇文章对您有所帮助!如果您有任何反馈或疑问,欢迎在下方评论区留言。

欲了解更多此类内容,请在Twitter上关注我

直到下一次

鏂囩珷鏉ユ簮锛�https://dev.to/ans human_bhardwaj/create-your-own-url-shortener-with-nextjs-and-mongodb-in-10-minutes-4fg
PREV
使用 TailwindCSS 在 React 中创建阅读进度条
NEXT
生产力助推器:我最值得购买的五大开发工具