Skip to content

Commit

Permalink
feat: 添加缓存,每次查询之后的24小时内都不需要查询外部接口
Browse files Browse the repository at this point in the history
  • Loading branch information
gantrol committed Dec 7, 2023
1 parent 7f36b53 commit ca8f41e
Show file tree
Hide file tree
Showing 5 changed files with 329 additions and 11 deletions.
293 changes: 293 additions & 0 deletions GPT问答记录/4实现结果缓存.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,293 @@
# 3实现搜索结果

## 问ChatGPT的问题

现在要用 Next.js 与 chakra.ui 建`whois`站,根据如下描述与已有代码,加上缓存处理,每次查询之后的24小时内都不需要查询外部接口,可以使用外部依赖包。

### 用户案例

假设用户想要一个带 gantrol 的域名,比较想要 gantrol.com,用户主要想得到什么情报呢?

- 这个域名的信息,最主要的是,有没有被注册、是否能买到
- 有没有相关域名可以注册

### 外部api

数据的结构决定代码的结构,必须了解数据,才能写出符合要求的代码。

```markdown
https://whois.freeaiapi.xyz/?name=${name}&suffix=${suffix}
```

示例:查询 gantrol.com,被拆分为 whois.freeaiapi.xyz/?name=gantrol&suffix=com

请求的返回分为两种,不清楚怎么调用接口的同学也先别急,可以用<https://whois.gantrol.com> 确认一下。

- available = true

```json
{
"status": "ok",
"name": "gantrol",
"suffix": "com",
"domain": "gantrol.com",
"creation_datetime": "2020-10-29T04:08:52Z",
"expiry_datetime": "2024-10-29T04:08:52Z",
"available": false,
"info": " Domain Name: GANTROL.COM\r\n Registry Domain ID: 2568931463_DOMAIN_COM-VRSN\r\n Registrar WHOIS Server: whois.paycenter.com.cn\r\n 《省略几百词》 .\r\n"
}
```

- available = false

```json
{
"status": "ok",
"name": "gantrol",
"suffix": "org",
"domain": "gantrol.org",
"creation_datetime": "",
"expiry_datetime": "",
"available": true,
"info": "Domain not found.\r\n>>> Last update of WHOIS database: 2023-12-05T08:58:08Z <<<\r\n\r\nTerms of Use:..《省略几百词》.\r\n"
}
```

### 基本界面设计

- 主页主体是Google极简风格的搜索框,商标位置先用文字“域名搜索”替代

- 用户搜索`gantrol.com` 后,网站跳转到`/whois/gantrol.com`,然后页面顶端是搜索框,其下是具体的域名信息

- "available": true,

### 已有代码

#### index.js

```jsx
import {Flex, Heading, IconButton, Input} from "@chakra-ui/react";
import {SearchIcon} from "@chakra-ui/icons";
import {useState} from "react";
import {useRouter} from "next/router";

export default function Home() {
const [domain, setDomain] = useState('');
const router = useRouter();

const handleSearch = () => {
if (domain) {
router.push(`/whois/${domain}`);
}
};

return (
<Flex
direction="column"
justify="center"
align="center"
height="100vh"
>
<Heading mb={4}>域名搜索</Heading>
<Flex
justify="center"
align="center"
// 添加间距
gap="2"
>
<Input
placeholder="输入域名"
value={domain}
// 当输入框的值改变时,更改 domain 的值
onChange={(e) => setDomain(e.target.value)}
// 基础屏幕尺寸下宽度为 90%(适用于较小屏幕的移动设备),以及中等屏幕尺寸(如平板或小型桌面显示器)下的宽度为 400px
width={{base: "90%", md: "400px"}}
/>
<IconButton
icon={<SearchIcon/>}
// 为按钮添加点击事件
onClick={handleSearch}
/>
</Flex>
</Flex>
);
}


```

### `src/pages/api/whois.js`

```javascript
// 导入 Next.js 的 API 路由支持
import { NextApiRequest, NextApiResponse } from "next";

// 处理 API 请求的函数
export default async function handler(req, res) {
// 从查询字符串中获取域名和后缀
const { domain } = req.query;

// 检查是否提供了域名和后缀
if (!domain) {
return res.status(400).json({ error: "缺少必要的参数:domain" });
}

// 解析域名和后缀
const [name, suffix] = domain.split(".");

// 构建外部 API 请求的 URL
const apiUrl = `https://whois.freeaiapi.xyz/?name=${name}&suffix=${suffix}`;

try {
// 使用 fetch 发送请求到外部 API
const response = await fetch(apiUrl);
const data = await response.json();

// 将获取到的信息返回给客户端
res.status(200).json(data);
} catch (error) {
// 处理可能发生的错误
res.status(500).json({ error: "服务器错误,无法获取域名信息" });
}
}
```

### `src/pages/whois/[domain].js`

```js
import { Box, Flex, Text, Spinner, Alert, AlertIcon } from "@chakra-ui/react";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";

export default function Whois() {
const router = useRouter();
const { domain } = router.query;
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const [domainInfo, setDomainInfo] = useState(null);

useEffect(() => {
if (domain) {
setLoading(true);
fetch(`/api/whois?domain=${domain}`)
.then(res => res.json())
.then(data => {
setDomainInfo(data);
setLoading(false);
})
.catch(error => {
console.error("Error fetching domain info:", error);
setError("无法获取域名信息,请稍后重试。");
setLoading(false);
});
}
}, [domain]);

if (loading) {
return <Spinner />;
}

if (error) {
return (
<Alert status="error">
<AlertIcon />
{error}
</Alert>
);
}

return (
<Flex direction="column" align="center" p={5}>
<Text fontSize="xl" mb={2}>域名信息查询结果</Text>
{domainInfo && (
<Box p={4} borderWidth="1px" borderRadius="lg">
<Text><b>域名:</b> {domainInfo.domain}</Text>
<Text><b>是否可注册:</b> {domainInfo.available ? "" : ""}</Text>
{domainInfo.creation_datetime && (
<Text><b>创建时间:</b> {domainInfo.creation_datetime}</Text>
)}
{domainInfo.expiry_datetime && (
<Text><b>过期时间:</b> {domainInfo.expiry_datetime}</Text>
)}
<Text><b>详细信息:</b></Text>
<Text whiteSpace="pre-wrap">{domainInfo.info}</Text>
</Box>
)}
</Flex>
);
}

```

## GPT 回答示例

> 注:回答不唯一
针对您的项目需求,我们可以通过添加简单的缓存逻辑来优化`whois`查询的性能。这样,每次用户进行域名查询时,我们首先检查缓存中是否存在该域名的信息,如果存在且未超过24小时,我们直接从缓存中返回数据,而不是重新查询外部API。这不仅提高了效率,也减少了对外部API的依赖和调用次数。

下面,我将为您展示如何实现这一功能:

### 1. 安装外部依赖

首先,我们需要一个用于缓存的库。`node-cache`是一个简单的缓存库,非常适合我们的需求。您可以通过运行以下命令来安装它:

```bash
npm install node-cache
```

### 2. 修改 `src/pages/api/whois.js`

在此文件中,我们将添加缓存逻辑。首先,在文件顶部导入`node-cache`,并实例化一个新的缓存对象:

```javascript
import NodeCache from "node-cache";
const myCache = new NodeCache({ stdTTL: 86400 }); // 缓存24小时
```

接下来,修改`handler`函数以使用缓存:

```javascript
export default async function handler(req, res) {
const { domain } = req.query;
if (!domain) {
return res.status(400).json({ error: "缺少必要的参数:domain" });
}

// 尝试从缓存中获取数据
const cachedData = myCache.get(domain);
if (cachedData) {
return res.status(200).json(cachedData);
}

// 缓存中没有数据,继续查询外部API
const [name, suffix] = domain.split(".");
const apiUrl = `https://whois.freeaiapi.xyz/?name=${name}&suffix=${suffix}`;

try {
const response = await fetch(apiUrl);
const data = await response.json();

// 将数据存储到缓存中
myCache.set(domain, data);

res.status(200).json(data);
} catch (error) {
res.status(500).json({ error: "服务器错误,无法获取域名信息" });
}
}
```

### 3. 测试

现在,当用户查询一个域名时,系统会首先检查缓存中是否有该域名的信息。如果缓存中有数据,并且数据未过期(24小时内),则直接返回缓存中的数据。否则,会向外部API发送请求,并将返回的数据存储在缓存中供未来使用。

### 4. 用户案例

针对用户想要的域名信息(比如`gantrol.com`),用户现在可以得到以下信息:

- 该域名是否已被注册、是否可购买
- 相关域名的可注册情况

由于我们已经添加了缓存机制,所以在24小时内对同一域名的查询不会再次调用外部API,从而加快了响应速度并减少了不必要的API调用。

以上就是对您项目中缓存功能的实现建议。希望这些信息对您有所帮助!
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

目前进度:实现主页、后端接口转发freeaiapi、搜索结果页。

- 部署到 Vercel: [![部署到 Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/gantrol/whois-nextjs/tree/step3&project-name=whois-nextjs&repository-name=whois-nextjs)
- 用Github在线编辑器打开:[![用Github在线编辑器打开](https://github.com/codespaces/badge.svg)](https://codespaces.new/gantrol/whois-nextjs/tree/step3)
- 部署到 Vercel: [![部署到 Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/gantrol/whois-nextjs/tree/step4&project-name=whois-nextjs&repository-name=whois-nextjs)
- 用Github在线编辑器打开:[![用Github在线编辑器打开](https://github.com/codespaces/badge.svg)](https://codespaces.new/gantrol/whois-nextjs/tree/step4)

## 基本分析

Expand Down
20 changes: 20 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@emotion/styled": "^11.11.0",
"framer-motion": "^10.16.12",
"next": "14.0.3",
"node-cache": "^5.1.2",
"react": "^18",
"react-dom": "^18"
}
Expand Down
22 changes: 13 additions & 9 deletions src/pages/api/whois.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
import NodeCache from "node-cache";
const myCache = new NodeCache({ stdTTL: 86400 }); // 缓存24小时

export default async function handler(req, res) {
// 从查询字符串中获取域名和后缀
const { domain } = req.query;

// 检查是否提供了域名和后缀
if (!domain) {
return res.status(400).json({ error: "缺少必要的参数:domain" });
}

// 解析域名和后缀
const [name, suffix] = domain.split(".");
// 尝试从缓存中获取数据
const cachedData = myCache.get(domain);
if (cachedData) {
return res.status(200).json(cachedData);
}

// 构建外部 API 请求的 URL
// 缓存中没有数据,继续查询外部API
const [name, suffix] = domain.split(".");
const apiUrl = `https://whois.freeaiapi.xyz/?name=${name}&suffix=${suffix}`;

try {
// 使用 fetch 发送请求到外部 API
const response = await fetch(apiUrl);
const data = await response.json();

// 将获取到的信息返回给客户端
// 将数据存储到缓存中
myCache.set(domain, data);

res.status(200).json(data);
} catch (error) {
// 处理可能发生的错误
res.status(500).json({ error: "服务器错误,无法获取域名信息" });
}
}

0 comments on commit ca8f41e

Please sign in to comment.