普通视图

发现新文章,点击刷新页面。
昨天 — 2026年2月13日首页

前端侦探:我是如何挖掘出网站里 28 个"隐藏商品"的?

作者 小冰球
2026年2月13日 11:36

前端侦探:我是如何挖掘出网站里 28 个"隐藏商品"的?

免责声明:本文仅供技术交流与学习,请勿利用文中技术手段对他人的服务器造成压力或进行恶意爬取。所有测试数据均来自公开接口。

🕵️‍♂️ 从一个好奇心开始

前几天逛一个数字产品合租平台(nf.video)时,我发现它首页只孤零零地挂着 6 个商品:Netflix、Disney+、Spotify 等常见的全家桶。

作为一个前端开发者,我的直觉告诉我:事情没这么简单

通常这类平台为了 SEO 或者后台管理的统一性,数据库里往往躺着更多商品,只是因为库存、策略原因被前端"隐藏"了。今天就带大家通过浏览器控制台(Console),用几招前端调试技巧,扒出那些藏在代码背后的秘密。


🔍 第一层:摆在明面上的数据

首先,我们看看普通用户能看到什么。打开控制台,简单查一下 DOM:

// 获取首页所有商品卡片
const cards = document.querySelectorAll('.platFormItem');
console.log(`首页可见商品数: ${cards.length}`);
// 输出: 6

确实只有 6 个。这建立了我们的"基准线"。如果后面我们找到了多于 6 个的数据,那就说明有"隐藏款"。


🎣 第二层:Vue Router 拦截术

点击商品卡片会跳转到购买页。通常我们会看 Network 面板找链接,但这个网站是 SPA(单页应用),点击是路由跳转。

为了不真的跳走(跳走就得退回来,麻烦),我们可以利用 Vue Router 的全局前置守卫来做一个"钩子"。我们想知道点击卡片后,路由到底想带我们去哪?

我们可以直接在控制台注入这段代码:

// 假设挂载在 app 上的 router 实例(视具体项目而定,通常在 vueApp.config 或 __vue_app__ 中)
// 这里演示思路
const router = document.querySelector('#app').__vue_app__.config.globalProperties.$router;

// 👮‍♂️ 注册一个拦截守卫
router.beforeEach((to, from, next) => {
    console.log(`🎯 捕获到目标路由: ${to.fullPath}`);
    console.log(`📦 参数 ID: ${to.params.id}`);
    
    // ✋ next(false) 阻止实际跳转,我们就停在当前页
    next(false); 
});

然后在页面上点击一个"苹果商店"的卡片:

Console 输出: 🎯 捕获到目标路由: /buy/31 📦 参数 ID: 31

Bingo!我们摸清了路由规则:/buy/:id。这意味着商品是以 ID 为索引的。


🕵️ 第三层:Performance API 里的蛛丝马迹

页面加载完了,Network 面板里的请求都被冲掉了或者很难找。这时,浏览器原生的 Performance API 就像一个黑匣子,记录了所有发生过的资源请求。

我想看看前端到底请求了哪些 API 接口:

// 筛选所有 XMLHttpRequest 或 Fetch 请求
const apiRequests = performance.getEntriesByType('resource')
  .filter(e => e.initiatorType === 'xmlhttprequest' || e.initiatorType === 'fetch')
  .map(e => e.name);

console.table(apiRequests);

在一堆日志里,我发现了这几个有趣的接口:

  • /api/applets/goods/get/homeManage (首页数据,估计就那 6 个)
  • /api/applets/goods/get/categoryGoods (分类商品?这个听起来有戏!)

我尝试手动调用了一下这个 categoryGoods 接口:

fetch('/api/applets/goods/get/categoryGoods')
  .then(res => res.json())
  .then(data => console.log(`拿到所有商品数: ${data.data.length}`));
// 输出: 27

27 个! 远超首页的 6 个。

通过分析返回的 JSON,我看到了大量首页没展示的商品:

  • ID 20: MagSafe 三合一无线充
  • ID 96: 银河次时代智能 NAS (这啥黑科技?)
  • ID 111: Typora 正版授权

到这里,如果是普通用户可能就满足了。但作为程序员,我注意到 ID 并不连续。最大的 ID 是 113,但中间缺了很多数字。

那些消失的 ID 去哪了?


🚀 第四层:ID 暴力枚举与深度挖掘

既然知道了 API 模式是 /api/applets/goods/get/:id,且 ID 是数字。那我能不能写个脚本,把 1 到 200 的 ID 全扫一遍?

这就像是在玩"扫雷"。

// 简单的并发探测脚本
async function scanHiddenGoods(maxId) {
    const hiddenGoods = [];
    
    console.log(`🚀 开始扫描 ID 1 - ${maxId}...`);
    
    const promises = [];
    for (let id = 1; id <= maxId; id++) {
        const p = fetch(`/8081/api/applets/goods/get/${id}`)
            .then(res => res.json())
            .then(res => {
                // 如果接口返回成功且有数据
                if (res.code === 10000 && res.data) {
                    return { id, name: res.data.goodsName, price: res.data.price };
                }
                return null;
            })
            .catch(() => null);
        promises.push(p);
    }

    const results = await Promise.all(promises);
    return results.filter(Boolean); // 过滤掉 null
}

// 让我们跑一下
scanHiddenGoods(200).then(goods => {
    console.table(goods);
    console.log(`🎉 共发现商品: ${goods.length} 个`);
});

几秒钟后,控制台打出了一张长长的表格。

结果令人震惊:

除了刚才分类列表里的 27 个,我又挖出了 8 个"幽灵商品"。这些商品连分类 API 都不返回,完全是"隐形"的,只有通过 ID 直达才能看到:

ID 名称 这居然也有?
18 GPT Plus 可能因为合规问题隐藏
26 Midjourney 只能直接访问购买
50 Runway 那个文生视频的 AI
105 Codex 编程神器

这些商品很可能是测试下架的、或者是仅限内部/老客户通过链接购买的。


📝 总结

通过这次探索,我们发现了网站里共有 34 个有效商品,而首页只展示了 17%

回顾一下我们的"作案工具":

  1. DOM 解析:看清表象。
  2. Vue Router 守卫:拦截路由,探知路径规则。
  3. Performance API:回溯历史请求,定位关键后端接口。
  4. Promise.all 并发探测:暴力枚举,发现离散数据。

前端开发不仅仅是画页面,善用浏览器提供的调试工具,我们可以对正在运行的应用有更深层的理解(或者单纯是为了满足好奇心 😉)。


如果你觉得这个分析过程有趣,欢迎点赞收藏!

❌
❌