ASP(经典 ASP,VBScript)IIS 中 工作机制
注意:这是SSI 服务器端包含,不是 ASP 的Server‑Execute/Server‑Include,是 IIS 解析阶段处理。
核心结论
是 IIS 在执行 ASP 脚本前,做文本合并(预处理器)**,不是运行时动态加载。
不会永久缓存合并后的脚本到 IIS 内存,但 ASP 有脚本缓存;文件改动会自动失效。
每一个请求到来:
IIS SSI 先把被 include 的文件原文文本插入主 asp 文件对应位置,拼接成一份完整的 ASP 源码。
交给 ASP 脚本引擎(asp.dll)编译执行。
如果该份拼接后的脚本没有被缓存,就编译;如果已经缓存,直接跑编译好的字节码。
⚠️重点:SSI 包含是文本级拼接,发生在脚本编译之前,不是运行时读文件。
详细过程(IIS 6 / IIS7 + 经典 ASP)
情况 A:文件没改动
用户请求 main.asp
IIS SSI 扫描 main.asp,遇到,读取磁盘上a.asp原始内容,把文本插入 main.asp 里面,得到完整源码。
asp.dll 检查:这份组合源码是否已经有编译缓存(Script Cache)
✅有缓存:直接执行编译好的脚本,不再重新解析、不重新 VBS 编译;但 SSI 这一步仍然要做(检查文件时间戳判断缓存是否有效)
❌无缓存:对拼接好的全部源码做编译,字节码放入 ASP 脚本缓存,供后续请求复用。
即使命中脚本缓存,IIS 仍然会访问磁盘读取 include 文件的文件时间戳,用来判断文件有没有修改;不需要读取完整文件内容,只拿文件属性。
情况 B:任意一个被 include 的 asp 文件修改了
只要main.asp、a.asp、b.asp其中任意一个磁盘文件修改,时间戳变化,ASP 缓存立刻作废。下一次请求会:
SSI 重新读取全部 include 文件文本,重新拼接完整源码
重新编译,生成新缓存。
情况 C:每请求都会完整读磁盘文件?
未命中缓存(文件刚改、冷启动):真实读磁盘,读取 include 文件全部内容,文本拼接。
命中缓存:只读取文件元信息(时间戳)校验,不读取整个文件内容,直接跑缓存字节码。
IIS 重启、应用池回收后,全部脚本缓存清空,下一次访问全部重新读文件 + 编译。
virtual vs file
<!--#include file="a.asp" --> '相对物理目录
<!--#include virtual="/inc/a.asp" --> '网站虚拟路径两者 SSI 处理逻辑完全一样,只是找文件方式不同,缓存机制无差别。
和 Server.Execute/ Server.Transfer 的区别
<% Server.Execute("a.asp") %>Server.Execute是运行时调用,不是 SSI 文本拼接,每次执行都会独立处理该页面,和#include完全不一样,不要混淆。
性能关键点(大量 include 的坑)
大量 include 不会导致每次请求都反复读全部文件内容(缓存命中后),但是每次请求都要做时间戳检查。几十个 include 文件,每个请求都要拿几十个文件的 last‑write 时间。
如果 include 极多(几十上百),高并发场景下,大量文件时间戳检查会带来一定磁盘 IO 压力。
只要任意一个被包含文件改动,整个页面缓存全部失效,下一次访问全部重新读文件编译。
SSI 是预处理,include 不能放在 if 判断里面!
<% If False Then %>
<!--#include file="debug.asp" --> '❌就算条件false,SSI仍然会把文件拼进来!!
<% End If %>SSI 在 VBS 运行之前就处理完毕,VBS 的逻辑控制不到#include。想条件包含只能用Server.Execute。
IIS 中 ASP 脚本缓存配置(IIS7+)
经典 ASP 缓存由ASP 脚本引擎控制:
Cache Scripts:True (默认开启),就是把编译后的字节码缓存内存;关闭的话,每一次请求都要读所有 include 文件、拼接、重新编译,性能暴跌。
Script File Cache Size:最大缓存多少脚本,站点 include 多页面多要调大。
这个缓存是应用池内存缓存,应用池回收就清空。不是 IIS 全局永久缓存。
总结一句话
有大量:冷启动 / 文件修改时,请求会读取所有被包含的磁盘文件文本做源码拼接;缓存命中之后,不会重读完整文件内容,只校验各个 include 文件的修改时间,直接运行内存中编译好的脚本。不是一次性永久加载到 IIS,应用池回收就全部清空重来。
也就是说,如果一个 asp 文件没被用到,IIS 是不会缓存它的,那么第一次访问这个 asp 文件才缓存?
是的,完全正确
经典 ASP 的脚本缓存是按需延迟缓存(惰性缓存):
文件不被请求到,就不会读、不会编译、不会进缓存。只有第一次实际执行到这个页面,才会触发整套流程:SSI 读取所有 include 文件 →拼接源码 →编译 →把字节码放进 ASP 脚本缓存。
