当网页翻页时,页码藏在哪里?——一次对分页机制的解密之旅

引言:一个奇怪的现象

最近我在使用一个在线题库网站准备考试时,发现了一个有趣的现象:点击"下一题"按钮时,页面内容更新了,但浏览器的地址栏URL完全没有变化 ,也没有看到常见的?page=2这样的页码参数。 这让我产生了好奇:网站是怎么知道我现在应该看第几页的呢?

作为一名技术爱好者,我决定像侦探一样,一步步揭开这个谜题。

第一步:查看网络请求

首先,我打开了浏览器的开发者工具(按F12),切换到"网络(Network)"标签页。当我点击"下一题"按钮时,我看到了一条POST请求:

arduino 复制代码
请求地址:https://www.freecram.com/.../exam-questions.html
请求方法:POST

关键发现1 :请求中并没有page=2pagenum=2这样的参数,而是只有三个字段:

  • recaptcha:我输入的验证码
  • do:值为+
  • csrftoken:一长串加密字符串

这就奇怪了!没有页码信息,服务器怎么知道我要看第几页呢?

第二步:查看页面代码

我回到页面,右键点击"查看网页源代码",找到了翻页相关的HTML代码:

html 复制代码
<form method="post">
    <!-- 验证码部分 -->
    <input type="text" name="recaptcha" placeholder="验证码">
    
    <!-- 提交按钮 -->
    <input type="submit" class="btn btn-sm" value="提交">
    
    <!-- 隐藏字段 -->
    <input type="hidden" name="do" value="+">
    <input type="hidden" name="csrftoken" value="...">
</form>

关键发现2 :表单中没有action属性,这意味着表单会提交到当前页面。但问题是,这个表单看起来只是用来提交验证码的,并没有页码信息。

接着我找到了控制翻页按钮的JavaScript代码:

javascript 复制代码
$('.prevqa').bind('click', function() {
    $('input[name=recaptcha]').focus();
});

关键发现3:翻页按钮只是让光标聚焦到验证码输入框,并没有直接提交表单或传递页码。

第三步:Cookie里的秘密

既然页面代码里没有明显线索,我转向了另一个方向:Cookie。在网络请求中,我看到了浏览器自动发送的一长串Cookie:

ini 复制代码
ASP.NET_SessionId=l2ojr0ozb0uyxmqvixoakslu
SessionID=d4d8e029-10fd-40e1-906c-7cfe5af848b4
MemberIntID=103215
...

这时我突然明白了!网站可能像餐厅给顾客安排桌号一样,通过一个"身份证"来识别每位用户。

第四步:会话(Session)的工作原理

让我用一个生活中的比喻来解释这个机制:

场景一:图书馆借书(传统分页方式)

  • 你告诉图书管理员:"我要借《三体》第二册"
  • 管理员直接给你第二册
  • 这里明确指定了"第二册"(就像page=2

场景二:图书馆连续阅读(当前网站的方式)

  1. 第一次来图书馆,管理员给你一个借阅卡号(SessionID)
  2. 你在登记本上写下:"看到《三体》第二册"
  3. 下次来时,你只需要说:"请给我下一册"
  4. 管理员查看登记本,知道你看完了第二册,就给你第三册

网站的工作方式就是第二种场景

  1. 首次访问:网站给你一个唯一的"借阅卡号"(存储在Cookie中的SessionID)
  2. 服务器记账:在服务器上记录"用户A看到第1页"
  3. 点击"下一页" :你告诉服务器"给我下一页"(通过do=+参数)
  4. 服务器查账:通过SessionID找到你的记录,知道你在看第1页,于是给你第2页
  5. 更新记录:在服务器上更新为"用户A看到第2页"

第五步:实验验证

为了验证这个理论,我做了几个实验:

实验一:清除Cookie测试

  1. 清除浏览器所有Cookie
  2. 重新访问同一套题链接
  3. 结果:从第1页重新开始!

结论:清除Cookie就像丢了"借阅卡",管理员不认识你了,只能从头开始。

实验二:隐身模式测试

  1. 用Chrome的隐身模式访问
  2. 做几道题,翻到第3页
  3. 新开一个隐身窗口访问同一链接
  4. 结果:新窗口从第1页开始!

结论:每个隐身窗口就像一个新顾客,有独立的"借阅卡"和阅读进度。

第六步:技术原理解析

现在让我们从技术角度看看这是如何实现的:

服务器端代码(伪代码)

py 复制代码
# 当用户首次访问时
def handle_first_visit(request):
    session_id = generate_unique_id()  # 生成唯一ID
    session_data = {
        'current_page': 1,
        'user_id': 103215,
        'start_time': '2026-03-09 00:41:29'
    }
    save_to_session_store(session_id, session_data)  # 保存到服务器
    set_cookie('ASP.NET_SessionId', session_id)  # 发给浏览器
    return render_page(1)  # 返回第1页

# 当用户点击"下一页"时
def handle_next_page(request):
    session_id = request.cookies.get('ASP.NET_SessionId')  # 获取SessionID
    session_data = load_from_session_store(session_id)  # 从服务器读取数据
    
    current_page = session_data['current_page']  # 获取当前页码
    new_page = current_page + 1  # 计算新页码
    
    session_data['current_page'] = new_page  # 更新页码
    save_to_session_store(session_id, session_data)  # 保存新状态
    
    return render_page(new_page)  # 返回新页面

数据传输流程

scss 复制代码
浏览器点击"下一页" → 发送Cookie(SessionID) + 表单数据(do=+) → 服务器
       ↑                                                  ↓
       ← 返回第N页HTML ← 服务器查找Session对应状态,计算N ←

第七步:为什么这样设计?

这种设计有多个优点:

1. 安全性

  • 用户无法通过修改URL直接跳转到任意页
  • 防止付费内容被随意访问
  • 考试时不能直接跳到最后一题看答案

2. 用户体验

  • URL简洁美观
  • 前进/后退按钮工作正常
  • 可以防止意外刷新导致进度丢失

3. 灵活性

  • 网站可以随时调整分页逻辑
  • 支持复杂的进度跟踪(答题对错、用时等)
  • 便于实现"断点续做"功能

第八步:其他可能的分页方式

除了这种"服务器记忆"的方式,网站还可以用其他方法实现分页:

方法A:URL参数(传统方式)

ini 复制代码
https://example.com/exam?page=2

优点:简单直接,可分享链接

缺点:暴露结构,可能被篡改

方法B:前端存储

使用浏览器的LocalStorage存储进度:

javascript 复制代码
// 存储
localStorage.setItem('current_page', 2);
// 读取
let page = localStorage.getItem('current_page');

优点:减轻服务器压力

缺点:清理浏览器数据会丢失进度

方法C:混合模式

结合多种方式,根据场景选择最适合的。

针对这种基于服务器端会话(Session) ​ 的爬取策略

方案一:使用Selenium自动化(最稳定)

  • 完全模拟真实浏览器行为
  • 自动处理Cookie和Session
  • 可以处理JavaScript渲染的内容
  • 可以截图验证码并使用OCR

方案三:逆向分析API接口(最高效)

  • 尝试找到底层的数据接口,绕过页面渲染。

策略

尝试找到底层的数据接口,绕过页面渲染。

结语:技术的艺术

通过这次探索,我发现了一个看似简单的"下一页"按钮背后,隐藏着一个精心设计的系统。就像魔术表演一样,观众只看到结果(页面切换),而魔术师(开发者)在幕后通过巧妙的机制(Session管理)实现了这个效果。

这种设计体现了Web开发中的一个重要原则:将状态管理放在最合适的地方。对于需要安全性、一致性和复杂状态跟踪的应用(如在线考试、购物车),服务器端Session管理是最佳选择。

下次当你使用网站时,不妨想想:这个简单的点击动作背后,有多少"看不见"的机制在默默工作?技术的美妙,往往就隐藏在这些看不见的细节中。

相关推荐
树上有只程序猿8 分钟前
2026低代码选型指南,主流低代码开发平台排名出炉
前端·后端
高端章鱼哥28 分钟前
为什么说用OpenClaw对打工人来说“不划算”
前端·后端
大脸怪28 分钟前
告别 F12!前端开发者必备:一键管理 localStorage / Cookie / SessionStorage 神器
前端·后端·浏览器
用户83562907805131 分钟前
使用 C# 在 Excel 中创建数据透视表
后端·python
boooooooom37 分钟前
讲清 Proxy + effect + track/trigger 流程
javascript·vue.js·面试
架构师沉默39 分钟前
别又牛逼了!AI 写 Java 代码真的行吗?
java·后端·架构
豆苗学前端1 小时前
彻底讲透浏览器缓存机制,吊打面试官
前端·javascript·面试
zone77391 小时前
006:RAG 入门-面试官问你,RAG 为什么要切块?
后端·算法·面试
swipe1 小时前
箭头函数与 this 面试题深度解析:从原理到实战
前端·javascript·面试
狗头大军之江苏分军2 小时前
消耗 760万 Token 后,一文看懂了“小龙虾” OpenClaw 和 OpenCode 的区别
前端·后端