学习目标:

  • 学习

        在前后端分离成为主流的今天,JSP(Java Server Pages)似乎成了 "时代的眼泪"。但回溯 2000-2015 年的 Java Web 黄金期,它却是无数开发者入门动态网页的第一块敲门砖 —— 不用手动拼接 HTML 标签,直接在网页里写 Java 代码,就能轻松实现用户登录、数据查询等功能。

然而,这种 "便捷性" 的背后,藏着从底层原理衍生的安全漏洞。今天我们就从 JSP 的本质讲起,拆解它的运行流程、核心逻辑,以及那些至今仍威胁着遗留系统的风险点。

一、JSP 的本质:

很多人误以为 JSP 是独立的技术,其实它只是Servlet 的 "语法糖"。要理解 JSP,必须先搞懂 Servlet 的痛点 ——

Servlet 是纯 Java 类,要输出 HTML 页面,得用out.println()一行行拼接标签,比如:

java

// 纯Servlet代码,开发效率极低
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<body>");
out.println("欢迎," + username); // 拼接动态内容
out.println("</body>");
out.println("</html>");

而 JSP 允许开发者在 HTML 中直接嵌入 Java 代码,比如:

jsp

<!-- JSP代码,HTML与Java无缝混合 -->
<html>
  <body>
    欢迎,<%= username %> <!-- 直接输出Java变量 -->
  </body>
</html>

核心真相:JSP 文件不会被直接执行。服务器会先把它翻译成 Servlet 源文件(.java),再编译成字节码文件(.class),最终运行的还是 Servlet。我们写的 JSP 代码,只是让服务器帮我们自动完成了 "Java 代码→Servlet" 的转换工作。

二、JSP 完整运行流程:4 步从请求到响应

当你在浏览器输入http://xxx.com/user.jsp时,服务器(比如 Tomcat)会按以下 4 个步骤处理,每一步都藏着关键技术细节:

1. 请求拦截:服务器判断是否需要编译

服务器收到 JSP 请求后,会先去 "工作目录"(比如 Tomcat 的work/Catalina/localhost/项目名/)找对应的字节码文件(如user_jsp.class):

  • 如果找到,且原 JSP 文件没有被修改过,直接跳过翻译和编译,执行字节码文件;
  • 如果没找到(第一次请求),或原 JSP 文件被修改过,就进入 "翻译→编译" 阶段。

小知识:开发时修改 JSP 后不用重启服务器,就是因为服务器会检测文件修改时间,自动重新翻译编译。

2. 翻译阶段:JSP→Servlet 源文件(.java)

服务器的 JSP 引擎(比如 Tomcat 的 Jasper)会逐行解析 JSP 代码,把不同类型的内容转换成 Java 代码:

JSP 语法作用转换后的 Java 代码示例
<% 代码 %>嵌入 Java 脚本(如循环、判断)直接放在 Servlet 的_jspService()方法中
<%= 变量 %>输出 Java 变量到 HTMLout.print(变量);
<%@ page ... %>页面指令(如导入包、设置编码)转换成类的注解或静态代码块
<jsp:include page="xxx.jsp"/>动态包含其他页面request.getRequestDispatcher("xxx.jsp").include(request, response);
普通 HTML 标签静态内容out.write("HTML标签");逐行输出

举个实际转换例子:原 JSP 代码:

jsp

<%@ page import="java.util.Date" %> <!-- 导入日期类 -->
<html>
  <body>
    当前时间:<%= new Date() %> <!-- 输出当前时间 -->
    <% if (new Date().getHours() < 12) { %> <!-- Java判断逻辑 -->
      <p>早上好!</p>
    <% } %>
  </body>
</html>

转换后的 Servlet 核心代码(简化版):

java

// 继承服务器提供的基础Servlet类
public class index_jsp extends org.apache.jasper.runtime.HttpJspBase {
  // 处理请求的核心方法
  public void _jspService(HttpServletRequest request, HttpServletResponse response) {
    // 初始化输出流(JSP的out内置对象)
    javax.servlet.jsp.JspWriter out = pageContext.getOut();
    try {
      response.setContentType("text/html");
      out.write("<html>\n");
      out.write("  <body>\n");
      out.write("    当前时间:");
      out.print(new Date()); // 对应<%= new Date() %>
      out.write("\n");
      if (new Date().getHours() < 12) { // 对应<% if (...) %>
        out.write("      <p>早上好!</p>\n");
      }
      out.write("  </body>\n");
      out.write("</html>");
    } catch (Exception e) {
      // 异常处理...
    }
  }
}

3. 编译阶段:Servlet 源文件→字节码(.class)

JSP 引擎调用 Java 编译器(javac),把生成的.java文件编译成.class字节码文件。这个字节码文件和普通 Java 类一样,会被服务器的类加载器加载到内存。

4. 执行阶段:生成响应返回浏览器

加载后的字节码文件会执行_jspService()方法(对应 Servlet 的service()方法),完成 3 件事:

  1. 通过request对象获取用户输入(如表单参数、URL 参数);
  2. 执行嵌入的 Java 代码(如查询数据库、处理业务逻辑);
  3. 通过out对象把动态内容(如时间、用户信息)嵌入 HTML,再通过response对象返回给浏览器。

三、JSP 核心逻辑:3 个简化开发的设计亮点

JSP 能成为 Java Web 的 "初代顶流",核心是它解决了 Servlet 的 3 个痛点,这些设计也是理解其漏洞的关键:

1. 内置对象:不用 new 就能用的 "工具集"

JSP 预定义了 9 个内置对象,开发者不用手动创建,直接在代码中使用,大幅减少重复代码。最常用的 5 个:

内置对象类型作用
requestHttpServletRequest获取用户请求数据(如参数、Cookie)
responseHttpServletResponse设置响应数据(如跳转、设置 Cookie)
sessionHttpSession存储用户会话信息(如登录状态)
outJspWriter向浏览器输出内容
pageContextPageContext获取其他内置对象,管理页面属性

比如要获取用户输入的 "用户名",直接写:

jsp

<% String username = request.getParameter("username"); %>

不用像 Servlet 那样手动声明HttpServletRequest对象。

2. 指令与动作元素:简化配置与页面复用

JSP 提供了专门的语法来处理配置和页面交互,不用写复杂的 Java 代码:

  • 指令元素:以<%@开头,用于页面全局配置,比如<%@ page contentType="text/html;charset=UTF-8" %>(设置页面编码)、<%@ include file="header.jsp" %>(静态包含头部页面);
  • 动作元素:以<jsp:开头,用于动态操作,比如<jsp:forward page="login.jsp"/>(页面跳转)、<jsp:param name="id" value="123"/>(传递参数)。

3. 生命周期自动管理:

JSP 对应的 Servlet 生命周期完全由服务器托管,开发者不用关心类的加载、实例化和销毁:

  • 初始化阶段:第一次被访问时,服务器调用jspInit()方法(可重写,用于加载配置、初始化资源);
  • 请求处理阶段:每次请求触发_jspService()方法(核心,处理业务逻辑);
  • 销毁阶段:服务器关闭或应用卸载时,调用jspDestroy()方法(可重写,用于释放资源,如关闭数据库连接)。

学习时间:

学习时间为学习时间

学习时间筋肉人
为学习时间future

内容为笔记【有时比较抽象,有时比较过于详细,请宽恕。作者可能写的是仅个人笔记,筋肉人future】  


学习产出:

  • 技术笔记 1遍
  • 有错误请指出,作者会及时改正

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐