浏览器早就不只是"看网页的窗口",它是一个装程序的容器。 静态的 HTML 文档只能"读",加上 JavaScript 之后页面能响应、能改自己,再接上后端的程序与数据库之后,它就变成了能"用"的东西——这就是 Web 应用:在线文档、邮箱、地图、协作文档,全都是跑在浏览器里的程序,你什么都没安装,却什么都能干。判据只有一句:给你看的 = 文档,给你用的 = Web 应用。 它凭什么赢过装在本机的软件?免安装、跨平台、服务器一改全员立刻新版、数据跟着账号走;代价是依赖网络、性能差一截、数据存在别人那里、随时可能被改掉或关停。
这一节是整章的收口——前面九节拆开的零件,在这里要拼成一个能用的东西:
- 4.2 的 HTML、4.3 的 CSS、4.4 的 URL、4.5/4.6 的 HTTP、4.7 的 Cookie:这些都是"一个 Web 应用"身上的一部分
- 4.1 那句"一次打开网页从来不是一次请求":本节要补上后半句——那几十上百个请求里,有很多是应用在后台自己发的(不是你在点)
- 4.8/4.9 那条"HTTPS 之后代理只剩信封":也正因为今天的主流 Web 应用都在 HTTPS 上,代理审核才只能看到域名那一层
- 最后和下层的账:1.5 讲的"应用程序是网络的主角",在这里有了最熟悉的一个例子
一、从"文档"到"应用":浏览器身份的变化
回顾 4.2:HTML 只干一件事——给内容贴标签。浏览器把标签解析成一棵树,然后按这棵树画页面。
那个阶段的浏览器,本质是一个排版阅读器。它做的事情是"把文档显示出来"。
变化发生在两处:
| 阶段 | 浏览器在干什么 | 你的角色 |
|---|---|---|
| ① 静态文档 | 把 HTML 显示出来 | 读(只能看) |
| ② + JavaScript | 页面能响应你的操作、还能改自己那棵树 | 操作(点了有反应) |
| ③ + 后端与数据 | 界面 + 逻辑 + 数据齐全,能完成一件完整的事 | 使用(这才是"应用") |
- 新闻页面:你读完就走 → 文档
- 在线文档编辑器:你写、它存、别人还能同时改 → Web 应用
- 电商网站:商品介绍页是文档,购物车和下单是应用 ——同一个网站里两种都有
所以"Web 应用"不是一个非黑即白的分类,而是一条谱系。越往"用"那头走,它就越像一个软件。
二、浏览器是怎么变成"应用容器"的
一个 Web 应用跑起来,靠的是四样东西各就各位(前三样你在 4.2、4.3 都见过):
| 能力 | 谁提供 | 干什么 |
|---|---|---|
| 结构 | HTML / DOM 树(收 4.2) | 内容与界面的骨架 |
| 外观 | CSS(收 4.3) | 长什么样 |
| 行为 | JavaScript | 能计算、能改 DOM、能发请求 —— "应用"的关键就在这一样 |
| 数据 | 后端程序 + 数据库 | 真正记账本的地方(收 4.7 的"账本在服务器") |
除此之外,浏览器还向网页开放了一批能力——你可以把它们想成浏览器发给网页的一个工具柜:
- 存东西:
localStorage、缓存(不用联网也能记住一些设置) - 画东西:
Canvas(在线画图、在线修图的底子) - 拿设备信息:当前位置、摄像头、麦克风、通知(每一次都要你点同意)
- 和服务器持续通话:
WebSocket(聊天、多人同时编辑文档靠它)
网页不能自己去翻你的硬盘、装驱动、改系统设置。它能做的每一件事,都得先由浏览器开口子——这就是"沙箱"。它既是 Web 应用"打不穿"的原因,也是它"干不了重活"的原因(第八节会算这笔账)。
三、一个操作背后,谁在干活
这是本节最该看懂的一张分工图:同一件事,被拆到了两个地方做。
| 浏览器这一侧 | 服务器这一侧 | |
|---|---|---|
| 负责 | 界面、交互、临时状态 | 业务规则、数据、会话 |
| 具体是 | HTML / CSS / JavaScript / Cookie / 缓存 | 后端程序 / 数据库 / 会话(收 4.7) |
| 看得见吗 | 你全都看得见(F12 一按就有) | 你一点都看不见 |
| 能改吗 | 你能改(改的是本机那份) | 只有运维能改 |
一条铁律,值得抄下来:
界面上写"最多能领 3 次",那是建议;真正管用的是服务器上那道检查。
同理:网页上的"密码强度校验""金额不能为负""你没有权限点这个按钮"——都只是体验。真正的判断必须在服务器那一侧。这条在 4.9 讲审计时也出现过同一张底牌:记录和裁判都在别人那一侧。
3.1 两种请求:整页重来 vs 只搬数据
| 整页请求 | 只搬数据 | |
|---|---|---|
| 要回来的是什么 | 一整个 HTML 文档 + CSS + JS + 图片 | 一小段数据(通常是 JSON) |
| 页面会闪一下吗 | 会(整页重画) | 不会(只是那一小块内容换了) |
| 什么时候用 | 第一次打开、按 F5 | 之后每一次操作 |
| 名字 | 传统页面跳转 | Ajax / fetch ——从"网页"变"应用"的分水岭 |
这里的 JSON 顺便值得认识一下:它是给程序吃的格式,长得像一堆键值对:
{ "now": "16:48:03", "user": "bozai", "unread": 2 }
对照 4.2 讲 HTML 的那句话就很清楚:HTML 是给人看的,JSON 是给程序吃的。 只不过两者进浏览器时都走同一套 HTTP(收 4.5),也都靠 Content-Type 告诉浏览器该怎么处理(收 4.6)——这一处正好把 4.6 那个"后缀 → 类型 → 浏览器行为"的链条又走了一遍。
四、Web 应用凭什么赢过"装在本机的软件"
| 装在本机的软件 | Web 应用 | |
|---|---|---|
| 安装 | 要下载安装包、点下一步 | 打开网址就能用 |
| 升级 | 手动更新(或替你自动更新) | 服务器一改,所有人立刻是新版 |
| 平台 | Windows 版 / Mac 版 / 手机版各来一份 | 一份代码,全平台都跑 |
| 数据在哪 | 在你自己硬盘上 | 在服务器上(换设备也在,但受制于人) |
| 离线能用吗 | 能 | 大多要联网 |
| 性能 | 能吃满本机硬件 | 差一截(受浏览器沙箱限制) |
| 能碰系统吗 | 能(装驱动、改设置) | 不能(关在沙箱里) |
这张表里有一条推论特别值得记住:
对开发者:不用为每个系统各做一份。 对用户:不用等更新、不用腾硬盘。
这两条加起来,就是为什么今天很多新软件只做网页版。
而收 1.8 的账也在这里对上了:SaaS 最常见的样子,就是一个 Web 应用——租来的软件,用浏览器打开。
五、代价也很实在:Web 应用的四笔账
好处说完了,另外半张脸也得看清:
- 服务器说改就改,你没有选择权。装在本机的软件,你可以不升级;Web 应用是"一次改动、全员生效"——昨天的用法今天可能就变了,而且没有"回退到旧版"这个选项。
- 数据存在别人那里。服务一关停,你的数据能不能拿回来,全看它有没有导出功能——所以"能不能导出"是一个服务值不值得用的硬指标。
- 离线就废。现在有 PWA / Service Worker 这类技术补一部分(能离线、能装到桌面像本地软件),但本质仍是补丁:数据最终还是要和服务器对齐。
- 它是很耗资源的一种"软件"。浏览器同时开几十个标签页,就是同时跑着几十个应用——每个都在吃内存和电。
前端代码(HTML、CSS、JavaScript)全都下载到了你的浏览器里,谁都能看。 所以:不要指望界面上的"隐藏"能守住秘密——F12 一按,都在那里(收 4.2 那条"F12 的元素面板和源码常常不一样",正面用是调试,反面用就是"前端没有秘密")。
六、站在网络这一侧看:Web 应用改了什么
这一点是本章最该带走的视角转换——Web 应用把网络的"流量形状"整个改掉了。
| 文档时代 | 应用时代 | |
|---|---|---|
| 请求次数 | 少 | 多 |
| 每次大小 | 大(整页 HTML + 图) | 小(一小段 JSON) |
| 频率 | 你点一下才有 | 你一敲键盘、一滚动就可能有一次 |
| 有没有"服务器主动推" | 没有,只能你去问 | 有(聊天、协作编辑:WebSocket) |
于是 4.1 那句话有了后半句:
一次打开网页从来不是一次请求——而在 Web 应用里,其中很大一部分请求根本不是你点的,是应用自己在后台发的(自动保存、消息轮询、状态同步、埋点统计)。
这也解释了 4.5 讲的无状态为什么在今天更重要:每次自动请求都要自己带上凭据(Cookie / Token,收 4.7),服务器那边不记得你是谁。
七、动手 Demo(Demo47):亲手看见"页面没刷新,内容却变了"
思路:用一个文件做一个最小的 Web 应用——一个页面 + 一个数据接口。点按钮时,页面上的时间会变,但整页不会刷新。这一眼,就是"网页"和"应用"的分界线。
第 1 步 · 新建 app_demo.py
import http.server
import json
import datetime
PAGE = """<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>最小 Web 应用</title>
</head>
<body>
<h1>这是一个 Web 应用</h1>
<p>服务器时间:<span id="t">(还没取)</span></p>
<p>你点了 <span id="n">0</span> 次</p>
<button id="btn">刷新时间(不刷新页面)</button>
<script>
let n = 0;
document.getElementById("btn").onclick = async () => {
const resp = await fetch("/api/time"); // 只取数据,不要整页
const data = await resp.json();
document.getElementById("t").textContent = data.now;
n = n + 1;
document.getElementById("n").textContent = n;
};
</script>
</body>
</html>
"""
class Handler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/api/time":
body = json.dumps(
{"now": datetime.datetime.now().strftime("%H:%M:%S")},
ensure_ascii=False).encode("utf-8")
ctype = "application/json; charset=utf-8"
else:
body = PAGE.encode("utf-8")
ctype = "text/html; charset=utf-8"
self.send_response(200)
self.send_header("Content-Type", ctype)
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def log_message(self, fmt, *args):
print("[服务器] " + fmt % args)
http.server.HTTPServer(("127.0.0.1", 8000), Handler).serve_forever()
第 2 步 · 起起来
python app_demo.py
第 3 步 · 打开页面
浏览器访问 http://127.0.0.1:8000。
第 4 步 · F12 → 网络面板 → 把筛选器点成 Fetch/XHR
第 5 步 · 连点几次"刷新时间"(本节核心现场)
你会看到:
- 页面上的时间变了、次数在涨
- 但页面没有闪,地址没变,整页没有重新加载
- 网络面板里只多出一条请求:
/api/time,返回的是一小段 JSON
对比一下就懂了:按一下 F5,网络面板里会多出一条 document 请求,而且页面整体重画一次。
"整页 document" 和 "一小段 fetch",就是网页与 Web 应用的分界。
第 6 步 · 点开那条 /api/time,看它的响应
{"now": "16:48:03"}
对照一下:4.2 那个 HTML 是给人看的(有标签、有结构),这一段是给程序吃的(只有数据)。同一条 HTTP 通道,运的东西不一样。
第 7 步 · 断网再点一次
点击后页面没反应,控制台报错——Web 应用对网络的依赖,就在这里。你本地那个 HTML 文件明明还在,可它没有数据可用了。
第 8 步 · 看后端那一侧的日志
app_demo.py 的窗口里,每点一次就落一行——你点的是界面,真正记事的在服务器(收 1.7 门房日志的老套路)。
八、30 秒实验
- 30 秒:
F12 → 网络面板 → 筛选Fetch/XHR`` —— 打开一个你常用的网站(邮箱、在线文档),什么都不点光看,也会有几个请求自己在跑。 - 30 秒:在同一个网站上做一次操作(收藏一条、改个设置)—— 数一数多出来的是 document 还是 fetch。这一眼就是"文档"和"应用"的分别。
- 30 秒:右键 → 查看网页源代码,再对照 F12 元素面板 —— 两处内容不一样(收 4.2):源码是"送来的那份",元素面板是"应用跑过之后的样子"。
九、常见误区
- "Web 应用就是把网页做得花哨一点。" —— 判据不是花不花哨,是它是给你读的还是给你用的、有没有跑在浏览器里的程序逻辑。
- "页面不刷新,就跟本地软件一样了。" —— 它仍然住在沙箱里:不能随意读写硬盘、不能改系统设置、每一次要设备能力都得你点同意。
- "Web 应用不用安装,所以什么都没存到我电脑上。" —— 缓存、
localStorage、Cookie(收 4.7)都在你电脑上,只是你"没做安装这个动作"而已。 - "浏览器里打开的都叫网页。" —— 浏览器里可能跑着应用,也可能是本地文件(
file://,收 4.2),还可能是个 PDF 阅读器。浏览器是个平台,不只干一件事。 - "Web 应用每次操作都要下载整个页面。" —— 主流做法是只取数据(JSON);每次整页重来反而是老旧的做法。
- "服务器改版了,我这边不受影响。" —— 一次改动全员生效正是它的特点,而且你没有"回退旧版"这个选项(本机软件可以做版本选择,Web 应用不行)。
- "数据放云端比放本机更安全。" —— 安全性取决于服务方怎么管,跟"在云端"没有必然关系;而且你同时把数据主权交了出去。
- "前端界面写"最多 3 次",那就只能 3 次。" —— 前端说的一切都在你的掌控范围内、也都能被改。真正的规则必须在服务器上判(本节第三节那条铁律)。
- "Web 应用性能天生就差,做不了正事。" —— 差的是"受沙箱与 JS 限制",但差距在缩小(
WebAssembly等),很多正经工作已经够用。 - "SaaS 和 Web 应用是两码事。" —— SaaS 最常见的样子就是一个 Web 应用:软件在别人服务器上跑(收 1.7/1.8),你用浏览器"租着用"。
十、动手自测
- 判断"文档"还是"Web 应用"的那条分界线是什么?
- 让静态页面变成"能用的东西",多了哪三样东西?
- 浏览器为什么不能随意读写你的硬盘?这带来什么好处、什么限制?
- 界面与交互在哪一侧跑?业务规则与数据在哪一侧跑?
- 为什么说"前端做的一切安全判断都不算数"?
- "整页请求"和"只搬数据"有什么差别?后者为什么是"网页到应用"的分水岭?
- Web 应用相比本机软件的四个优势、四个代价各是什么?
- 为什么说"安装这件事被消灭了"?这对应 1.8 的哪一类云服务?
- Web 应用把网络流量的形状改成了什么样?
- 为什么"查看网页源代码"和 F12 元素面板里看到的不一样?
答案:
① 给你看的 = 文档;给你用的 = Web 应用。 它是一条谱系而不是非黑即白:一个网站里常常两种都有(商品详情页是文档、购物车是应用)。② JavaScript(行为:能计算、能改 DOM、能发请求)、后端程序(业务规则)、数据库(真正的数据账本)。前两样让页面"活"起来,第三样让它"记得住"。③ 因为网页的能力全部由浏览器开口子——它够不到沙箱之外(沙箱)。好处是打不穿(网页再坏也翻不了你的硬盘);限制是干不了重活(装驱动、深度读写文件都不行)。④ 界面与交互在浏览器里跑(HTML/CSS/JavaScript、Cookie、缓存);业务规则和数据在服务器上跑(后端程序、数据库、会话,收 4.7)。⑤ 因为前端的一切都下载到了你的浏览器里、全在你掌控之下、也都能被改。"密码校验""金额不能为负""没有权限"写在界面上只是体验;真正的判断必须在服务器上——和 4.9 那条"记录与裁判都在别人那一侧"是同一张底牌。⑥ 整页请求要回一整个 HTML 文档 + CSS + JS + 图片、页面会闪;只搬数据只要回一小段 JSON、页面不闪。因为页面不重画却内容变了,用户感受到的就不再是"翻了一页",而是"点了个按钮应用响应了"——这就是从"网页"变成"应用"的那一步(fetch / Ajax)。⑦ 优势:免安装 / 服务器一改全员立刻新版 / 一份代码全平台 / 数据跟着账号走(换设备还在)。代价:依赖网络(大多离线就废)/ 性能差一截 / 数据在别人那里(服务关停可能拿不回来,所以"能不能导出"是硬指标)/ 说改就改、没有版本选择权。⑧ 因为开发者不用为每个系统各做一份、用户不用下载安装也不用等更新——打开网址就能用。对应 1.8 的 SaaS:软件在别人服务器上跑,你用浏览器租着用。⑨ 从"请求少而大、你点一下才有",变成"请求多而小、还很频繁(你一敲键盘、一滚动就可能有一次),并且出现服务器主动推(WebSocket,聊天与协作编辑)"。这也是 4.1 那句"一次打开网页几十上百次请求"的后半句:其中很大一部分根本不是你点的(自动保存、状态同步、埋点)。⑩ 源码是服务器送来的那份静态文本;元素面板是应用(JavaScript)跑过之后那棵 DOM 树的样子——脚本改的是树,硬盘上的 .html 一个字没变(收 4.2)。
十一、下一步学什么
- ☑ 浏览Web网站时的准备工作(访问Web时使用的应用软件与协议) —— 本节换个角度把整章点了一遍名:访问一个网站要先就位"一个会用 HTTP 的客户端 + 一套配好的协议"。浏览器其实是一堆客户端拼起来的(缓存、Cookie、DNS、TCP、TLS、HTTP、渲染各一个模块);敲下回车后六步依次上岗,一次访问至少动五个层。最后落在一张"网页打不开该先查哪儿"的对照表上。
相关笔记
- 审核公司员工浏览的Web网站(代理服务器的用途) —— 上一节:Web 应用大多跑在 HTTPS 上,这正是代理审核只能看到域名那一层的原因
- 制作Web网页(HTML) —— HTML 是"文档"那一侧的基础;DOM 树正是脚本能改的那棵树
- 设计Web网页的外观(样式表) —— 界面这一层怎么来的;样式与结构分离才有"应用"规模的可维护性
- Web网站是如何构建的(Web网站) —— 一次打开网页的几十上百次请求:本节补上后半句,其中很多是应用在后台自己发的
- 请求Web网站的文件(HTTP) —— 应用每次自动请求都要自带凭据,因为 HTTP 是无状态的
- 传输Web网站的文件(HTTP响应) ——
Content-Type决定"给人看的 HTML"还是"给程序吃的 JSON"怎么处理 - 记录Web网站的文件(HTTPCookie) —— 应用的状态(登录、购物车)靠这张纸条串起来;账本在服务器
- Web网站的地址(URL) —— 应用也用同一套地址;接口就是那些返回 JSON 的 URL
- 是谁在负责收发数据(应用程序、P2P应用) —— "应用程序是网络的主角",Web 应用是最熟悉的一个例子;它的"客户端"就是浏览器
- 使用服务器的哪个部分?云服务的分类(SaaS、PaaS、IaaS) —— SaaS 最常见的样子就是一个 Web 应用
- 运行和管理服务器(服务器、云服务、内部部署) —— 后端程序与数据库就住在这些服务器上
- 根据端口号分配数据到应用程序(端口号、已知端口号) —— 本地起一个后端,"门牌号"就是那个端口(Demo 里的 8000)
- 对应用程序的数据进行可靠传输(TCP) —— 应用层的这些来回,脚下仍然是 TCP 在保送达
- 用于构建网络的设备(网络设备) —— 应用层的能力,最终都落在这些设备与主机上跑