forked from lunanting/cangku
95 lines
2.4 KiB
JavaScript
95 lines
2.4 KiB
JavaScript
const crypto = require('crypto');
|
|
const express = require('express');
|
|
const {
|
|
getTaobaoDetailPlusByItemId,
|
|
} = require('../services/taobaoDetailPlusDataService');
|
|
|
|
const router = express.Router();
|
|
|
|
function getConfiguredApiKeys() {
|
|
return [
|
|
process.env.TAOBAO_DETAIL_PLUS_API_KEY,
|
|
process.env.TAOBAO_DETAIL_PLUS_API_KEYS,
|
|
]
|
|
.filter(Boolean)
|
|
.flatMap((value) => String(value).split(','))
|
|
.map((value) => value.trim())
|
|
.filter(Boolean);
|
|
}
|
|
|
|
function safeEquals(left, right) {
|
|
const leftBuffer = Buffer.from(String(left || ''));
|
|
const rightBuffer = Buffer.from(String(right || ''));
|
|
if (leftBuffer.length !== rightBuffer.length) {
|
|
return false;
|
|
}
|
|
return crypto.timingSafeEqual(leftBuffer, rightBuffer);
|
|
}
|
|
|
|
function extractApiKey(req) {
|
|
const headerKey = req.get('x-api-key');
|
|
if (headerKey) {
|
|
return headerKey.trim();
|
|
}
|
|
|
|
const authHeader = req.get('authorization') || '';
|
|
const match = authHeader.match(/^(?:ApiKey|Bearer)\s+(.+)$/i);
|
|
if (match) {
|
|
return match[1].trim();
|
|
}
|
|
|
|
return String(req.query.apiKey || req.query.api_key || '').trim();
|
|
}
|
|
|
|
function requireApiKey(req, res, next) {
|
|
const configuredKeys = getConfiguredApiKeys();
|
|
if (configuredKeys.length === 0) {
|
|
return res.status(503).json({
|
|
success: false,
|
|
error: '接口 API key 尚未配置',
|
|
});
|
|
}
|
|
|
|
const providedKey = extractApiKey(req);
|
|
if (!providedKey || !configuredKeys.some((key) => safeEquals(providedKey, key))) {
|
|
return res.status(401).json({
|
|
success: false,
|
|
error: 'API key 无效或未提供',
|
|
});
|
|
}
|
|
|
|
return next();
|
|
}
|
|
|
|
async function handleDetailQuery(req, res) {
|
|
try {
|
|
const itemId = req.params.itemId || req.query.itemId || req.query.item_id || req.query.num_iid;
|
|
const data = await getTaobaoDetailPlusByItemId(itemId);
|
|
if (!data) {
|
|
return res.status(404).json({
|
|
success: false,
|
|
error: '未找到该商品数据',
|
|
});
|
|
}
|
|
|
|
return res.json({
|
|
success: true,
|
|
data,
|
|
});
|
|
} catch (error) {
|
|
const statusCode = error.statusCode || 500;
|
|
if (statusCode >= 500) {
|
|
console.error('[TaobaoDetailPlusAPI] 查询失败:', error);
|
|
}
|
|
return res.status(statusCode).json({
|
|
success: false,
|
|
error: error.message || '查询商品详情失败',
|
|
});
|
|
}
|
|
}
|
|
|
|
router.get('/', requireApiKey, handleDetailQuery);
|
|
router.get('/:itemId', requireApiKey, handleDetailQuery);
|
|
|
|
module.exports = router;
|