feat: 搜索接口做redis缓存

This commit is contained in:
mazxd
2025-05-15 00:24:49 +08:00
parent 38a5c69a37
commit 7342e18eb5
4 changed files with 443 additions and 28 deletions
+81 -14
View File
@@ -56,23 +56,90 @@ export class SearchService {
@handleError('搜索执行失败')
public async search(keyword: string): Promise<SearchResponse> {
logger.info('开始执行搜索', { keyword });
const token = await this.getToken();
const response = await axios.get<SearchResponse>(
`${this.baseUrl}${config.searchService.endpoints.search}`,
{
params: { keyword },
headers: {
Authorization: `Bearer ${token}`,
},
// 1. 尝试从Redis获取缓存
const cacheKey = `search:${keyword}`;
const cachedResult = await this.redisService.get(cacheKey);
if (cachedResult) {
logger.info('从缓存中获取搜索结果', { keyword });
return JSON.parse(cachedResult);
}
// 2. 获取token并执行搜索
let token = await this.getToken();
let retryCount = 0;
const maxRetries = 1;
while (retryCount <= maxRetries) {
try {
const response = await axios.get<SearchResponse>(
`${this.baseUrl}${config.searchService.endpoints.search}`,
{
params: { keyword },
headers: {
Authorization: `Bearer ${token}`,
},
}
);
// 3. 处理搜索结果
if (response.data.success && response.data.data) {
// 为每个结果项生成唯一ID并格式化数据
const processedData = response.data.data.map(channelData => {
const processedList = channelData.list.map(item => {
const itemId = crypto.randomUUID();
const processedItem = {
itemId,
driveType: item.cloudLinks?.[0]?.cloudType?.toLowerCase() || 'unknown',
publishDate: new Date(item.pubDate).toISOString(),
displayTitle: item.title,
...item
};
// 将单个结果项存入Redis,TTL设置为1天
this.redisService.set(`item:${itemId}`, JSON.stringify(processedItem), { EX: 86400 })
.catch(err => logger.error('缓存单个结果项失败', { error: err, itemId }));
return processedItem;
});
return {
...channelData,
list: processedList
};
});
// 4. 将完整搜索结果存入Redis,TTL设置为5分钟
const searchResult = {
...response.data,
data: processedData
};
await this.redisService.set(cacheKey, JSON.stringify(searchResult), { EX: 3600 });
logger.info('搜索完成', {
keyword,
resultCount: processedData.reduce((acc, channel) => acc + channel.list.length, 0)
});
return searchResult;
}
throw new AppError('搜索结果格式错误', 500);
} catch (error: any) {
// 处理token失效的情况
if (error.response?.status === 401 || error.response?.status === 403) {
if (retryCount < maxRetries) {
logger.warn('Token已失效,尝试重新获取', { retryCount });
token = await this.getToken();
retryCount++;
continue;
}
}
throw error;
}
);
}
logger.info('搜索完成', {
keyword,
resultCount: response.data.data?.length || 0
});
return response.data;
throw new AppError('搜索失败,请稍后重试', 500);
}
@handleError('参数化搜索失败')