在本文中,将详细介绍如何在 Vercel 平台上部署一个具有分类功能的随机图片 API。通过这个 API,用户可以根据不同的分类获取随机图片链接,并且还可以从所有分类中随机获取一张图片。

项目结构

首先,我们需要确定项目的目录结构,如下所示:

random-image-api/
├── api/
│   ├── meinv.txt
│   ├── dongman.txt
│   ├── randomImage.js
├── public/
│   ├── index.html
│   ├── favicon.ico
├── package.json
└── vercel.json

1. 准备分类文本文件

api 目录下创建 meinv.txtdongman.txt 文件,并在每个文件中添加图片链接,每行一个链接。例如:

当然你也可以自己创建新分类,只要格式为.txt就行

meinv.txt

https://example.com/meinv1.jpg
https://example.com/meinv2.jpg

dongman.txt

https://example.com/dongman1.jpg
https://example.com/dongman2.jpg

2. 创建 randomImage.js

api 目录下创建 randomImage.js 文件,并添加以下代码:

const express = require('express');
const fs = require('fs');
const path = require('path');
const cors = require('cors');

const app = express();

// 使用cors中间件
app.use(cors({
  origin: '*'
  // 或者指定特定的域名
  // origin: 'https://www.api1.link'
}));

// 从public目录中读取静态文件
app.use(express.static('public'));

// 从指定文件中获取随机图像链接的函数
const getRandomImage = (filePath) => {
  return new Promise((resolve, reject) => {
    fs.readFile(filePath, 'utf8', (err, data) => {
      if (err) {
        reject(err);
      } else {
        const lines = data.split('\n').filter(line => line.trim() !== '');
        const randomLine = lines[Math.floor(Math.random() * lines.length)];
        resolve(randomLine);
      }
    });
  });
};

// 从所有文本文件中随机获取图片链接的函数
const getRandomImageFromAllFiles = () => {
  return new Promise((resolve, reject) => {
    const dirPath = path.join(__dirname);
    fs.readdir(dirPath, (err, files) => {
      if (err) {
        reject(err);
      } else {
        const txtFiles = files.filter(file => file.endsWith('.txt'));
        if (txtFiles.length === 0) {
          reject(new Error('No text files found'));
        } else {
          const promises = txtFiles.map(file => getRandomImage(path.join(dirPath, file)));
          Promise.all(promises)
            .then(results => {
              const allImages = results.flat();
              const randomImage = allImages[Math.floor(Math.random() * allImages.length)];
              resolve(randomImage);
            })
            .catch(reject);
        }
      }
    });
  });
};

// 所有类别随机图像的路由
app.get('/random', async (req, res) => {
  try {
    const imageUrl = await getRandomImageFromAllFiles();
    res.redirect(imageUrl);
  } catch (error) {
    res.status(404).send('No images found');
  }
});

// 主页文档的默认路由
app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname, '../public/index.html'));
});

// 指定类别随机图像的路由
app.get('/:category', async (req, res) => {
  const category = req.params.category;
  const filePath = path.join(__dirname, `${category}.txt`);

  try {
    const imageUrl = await getRandomImage(filePath);
    res.redirect(imageUrl);
  } catch (error) {
    res.status(404).send('Category not found');
  }
});

module.exports = app;

3. 创建 index.html

public 目录下创建 index.html 文件,内容如下:

<!DOCTYPE html>
<html lang="zh-CN">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>随机图 | API</title>
        <link rel="icon" href="/favicon.ico">
        <style>
            html,
            body {
                margin: 0;
                color: #424242;
                font-weight: 300;
                font-family: "-apple-system", "BlinkMacSystemFont",
                    "Helvetica Neue", "PingFang SC", "Microsoft YaHei",
                    "Source Han Sans SC", "Noto Sans CJK SC",
                    "WenQuanYi Micro Hei", "sans-serif";
                font-size: 16px;
            }

            * {
                box-sizing: border-box;
            }

            header {
                padding: 40vh 0 8vh 0;
                text-align: center;
                font-weight: 100;
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: space-between;
                height: 100vh;
                overflow: hidden;
                background: #a0e5e4;
            }

            h1,
            h2,
            h3 {
                font-weight: 400 !important;
                font-weight: bold;
                margin: 0;
            }

            h1 {
                font-size: 3.5rem;
                padding: 20px;
            }

            h2 {
                font-size: 2rem;
                font-weight: 300;
                text-align: center;
            }

            h3 {
                font-size: 1.5rem;
                font-weight: 300;
            }

            #scroll-down {
                background-color: transparent;
                margin-top: 2rem;
                width: 2rem;
                height: 2rem;
                border-radius: 50%;
                border: 2px solid #424242;
                cursor: pointer;
                animation: bounce 2s infinite 2s;
            }

            #scroll-down::before {
                display: block;
                content: "";
                transform: rotate(-45deg) translate(0.15rem, 0.15rem);
                width: 0.4rem;
                height: 0.4rem;
                border: 2px solid #424242;
                border-width: 0px 0 2px 2px;
            }

            a {
                text-decoration: none;
                color: #5fbf62;
                font-weight: bold;
            }

            p {
                font-size: 18px;
                line-height: 1.6;
            }

            main {
                padding: 1vw;
            }

            section {
                padding: 1rem;
            }

            footer {
                padding: 1vh;
                text-align: center;
                background-color: #aaaaaa;
            }

            footer a {
                color: #1e03ea;
            }

            footer a:hover {
                text-decoration: underline;
            }

            @keyframes bounce {
                0%,
                100%,
                20%,
                50%,
                80% {
                    transform: translateY(0);
                }

                40% {
                    transform: translateY(-10px);
                }

                60% {
                    transform: translateY(-5px);
                }
            }
        </style>
    </head>

    <body>
        <header>
            <section>
                <h1>随机图 | API</h1>
                <h3>使用文档</h3>
            </section>
            <button id="scroll-down"></button>
        </header>
        <main>
            <section>
                <h2>随机图片 API</h2>
                <p>欢迎使用随机图片 API!你可以通过以下路径获取随机图片:</p>
                <ul>
                    <li><strong>/random</strong> - 随机获取 <a>一张</a> 图片</li>
                    <li><strong>/meinv</strong> - 随机获取 <a>美女</a> 图片</li>
                    <li><strong>/dongman</strong> - 随机获取 <a>动漫</a> 图片</li>
                </ul>
                <p>示例:</p>
                <ul>
                    <li>
                        <a href="/random" target="_blank"
                            >https://your-domain.vercel.app/random</a
                        >
                    </li>
                    <li>
                        <a href="/meinv" target="_blank"
                            >https://your-domain.vercel.app/meinv</a
                        >
                    </li>
                    <li>
                        <a href="/dongman" target="_blank"
                            >https://your-domain.vercel.app/dongman</a
                        >
                    </li>
                </ul>
            </section>
        </main>
        <script>
            document
                .getElementById("scroll-down")
                .addEventListener("click", function () {
                    document.querySelector("main").scrollIntoView({
                        behavior: "smooth",
                    });
                });
        </script>
        <footer>
            <p>
                <a href="https://github.com/aizhiqian">Github</a>
            </p>
        </footer>
    </body>
</html>

4. 添加 favicon.ico

favicon.ico 文件放在 public 目录下。你可以使用任意图标生成工具生成 favicon.ico 文件。

5. 创建 package.json

在项目根目录下创建 package.json 文件,内容如下:

{
  "name": "random-image-api",
  "version": "1.0.0",
  "main": "api/randomImage.js",
  "dependencies": {
    "express": "^4.19.2",
    "cors": "^2.8.5"
  }
}

6. 创建 vercel.json

在项目根目录下创建 vercel.json 文件,内容如下:

{
  "version": 2,
  "builds": [
    {
      "src": "api/randomImage.js",
      "use": "@vercel/node"
    },
    {
      "src": "/public/**",
      "use": "@vercel/static"
    }
  ],
  "routes": [
    {
      "src": "/",
      "dest": "/public/index.html"
    },
    {
      "src": "/favicon.ico",
      "dest": "/public/favicon.ico"
    },
    {
      "src": "/(.*)",
      "dest": "/api/randomImage.js"
    }
  ]
}

7. 部署到 Vercel

当然你也可以创建一个新的 Github 仓库,把代码推送到该仓库,然后在 Vercel 中选择该仓库直接部署。

这样你就不需要执行下述命令了。

在项目根目录中,打开终端并运行以下命令以部署到 Vercel:

npm install -g vercel
vercel

按照提示登录或注册 Vercel 账号,并选择你的项目配置。部署完成后,你将获得一个域名。通过访问该域名及其路径,你可以实现上述功能。

例如:

  • https://your-domain.vercel.app/ 显示项目的主页

  • https://your-domain.vercel.app/random 获取所有 .txt 文件中的随机图片

  • https://your-domain.vercel.app/meinv 获取 “meinv.txt” 文件中的随机图片

  • https://your-domain.vercel.app/dongman 获取 “dongman.txt” 文件中的随机图片

  • https://your-domain.vercel.app/新分类 获取 “新分类.txt” 文件中的随机图片


这样,你就成功创建并部署了一个具有分类功能的随机图片 API,并添加了主页说明文档。希望这篇文章能帮助你在 Vercel 上轻松部署你的随机图片 API。