【HTML分离术】
发现一种新的HTML页面实现:框架与内容的“分离术”
最近在爬取一个网站的内容时,遇到了个挺有意思的现象:用工具请求某个URL拿到的HTML源码里,<body>
标签里空空如也;即使在浏览器里开启JS重新加载,查看“页面源码”依然是空的——但页面上明明展示着丰富的内容。
一番折腾后才发现,这居然是一种新的HTML实现思路:页面本身只保留最基础的框架,<body>
里的内容完全靠前端JS从服务端接口动态拉取并渲染。
一、发现过程:“消失”的body内容
事情的起因是想获取某个页面的文本内容。我习惯性地用curl
请求URL,返回的HTML长这样:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><!-- 可能还有一些CSS/JS引用 --></head><body></body>
</html>
<body>
里只有一个空格,这显然不对——浏览器里明明有内容啊。
我又试着在浏览器里打开页面,右键“查看页面源码”,结果和curl
返回的一样,<body>
还是空的。但打开开发者工具看“Elements”面板,<body>
里却塞满了各种标签。
这时候才反应过来:页面的内容根本不是服务端直接渲染在HTML里的,而是页面加载后,通过JS调用接口拿到数据,再动态插入到<body>
中的。
二、核心实现:框架与内容的彻底分离
这种实现的核心逻辑很简单,拆成两步看:
1. 前端:只有“空壳”的HTML框架
服务端返回的HTML是个纯粹的“空壳”,除了<head>
里的基础配置(字符集、CSS/JS引用等),<body>
里没有任何实际内容。就像用户提供的这个模板:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><!-- 引入必要的JS(比如请求接口的工具库) --><script src="app.js"></script></head><body><!-- 这里啥也没有,等JS来填 --></body>
</html>
2. 内容加载:JS动态请求+渲染
页面加载完成后,app.js
里的代码会主动调用服务端的内容接口(比如/api/page-content
),拿到需要展示的内容(可能是HTML片段,也可能是JSON数据),再通过document.body.innerHTML
或DOM操作插入到<body>
中。
举个简单的实现例子(app.js
):
// 页面加载完成后请求内容
window.onload = async () => {try {// 调用接口获取内容(假设返回HTML片段)const res = await fetch('/api/page-content');const contentHtml = await res.text();// 插入到body中document.body.innerHTML = contentHtml;} catch (err) {document.body.innerHTML = '<div>内容加载失败</div>';}
};
这样一来,用户在浏览器里看到的内容,其实是JS动态“填”进去的——所以“页面源码”里看不到,只有“Elements”面板能看到最终渲染结果。
三、这种方式的优缺点:什么时候该用?
任何技术方案都有其适用场景,这种“空壳+接口拉取”的方式也不例外。
优点:
- 前后端彻底解耦:HTML框架和内容完全分离,前端负责渲染逻辑,后端只需要提供内容接口,迭代时互不干扰。
- 内容动态更新:内容变化时不需要重新发布HTML,直接更新接口返回值即可,适合高频更新的场景(比如新闻、活动页)。
- 轻量初始加载:HTML框架体积极小,首屏能快速完成基础加载,再异步拉取内容(配合加载动画体验更好)。
缺点:
- 首屏体验风险:如果JS加载失败或接口超时,
<body>
会一直是空的,用户看到的就是白屏。 - SEO不友好:传统搜索引擎爬虫大多不会执行JS,无法抓取动态插入的内容,导致页面在搜索结果中“隐形”(除非配合SSR或预渲染)。
- 依赖JS运行环境:必须在支持JS的浏览器中才能正常显示,对无JS环境(比如部分爬虫、极简浏览器)不兼容。
适用场景:
- 后台管理系统(对SEO无要求,用户都是登录状态,JS必开);
- 内容高频更新的页面(比如实时榜单、活动详情);
- 单页应用(SPA)的子页面内容加载(减少整体包体积)。
四、总结:一种“反直觉”的思路
这种实现方式初看挺“反直觉”——HTML居然可以没有内容?但细想下来,它其实是前端工程化发展的一个缩影:从早期服务端“包办”HTML渲染,到前后端分离,再到现在框架与内容的彻底拆分。
不过用的时候得想清楚:你的页面是否真的不需要搜索引擎收录?用户是否能接受“JS加载失败即白屏”的风险?如果答案都是肯定的,那这种“空壳+接口”的方式,或许能给你带来更灵活的开发体验。
毕竟,技术没有绝对的好坏,只有适合与否。