跳转至

Java Web 基础

2292 个字 预计阅读时间 11 分钟

Java EE(Java Platform, Enterprise Edition)是一套基于 Java 编程语言的应用程序开发平台,用于开发和部署大型分布式多层架构的企业应用。Java EE Java SE 的扩展,提供了一组 API 和运行时环境,用于构建、部署和管理企业级应用程序。2017 年的 9 Oracle Java EE捐赠给 Eclipse 基金会,由于 Oracle 持有 Java 商标原因,Eclipse 基金于 2018 3 月将Java EE更名为 Jakarta EE

Java EE Wiki

Servlet Wiki

Request & Response

今天我们访问网站,使用 App 时,都是基于 Web 这种 Browser/Server 模式,简称 BS 架构,它的特点是,客户端只需要浏览器,应用程序的逻辑和数据都存储在服务器端。浏览器只需要请求服务器,获取 Web 页面,并把 Web 页面展示给用户即可。

B/S架构中最重要的就是浏览器和服务器端交互,Java EE将其封装为请求响应对象,即 request(HttpServletRequest)response(HttpServletResponse)

HttpServletRequest对象用于处理来自客户端的请求,当客户端通过 HTTP 协议访问服务器时,HTTP 中的所有信息都封装在这个对象中,通过HttpServletRequest对象可以获取到客户端请求的所有信息。

HttpServletResponse对象用于响应客户端的请求,通过HttpServletResponse对象可以处理服务器端对客户端请求响应。

HttpServletRequest

HttpServletRequest封装了一个 HTTP 请求,它实际上是从ServletRequest继承而来。最早设计 Servlet 时,设计者希望 Servlet 不仅能处理 HTTP,也能处理类似 SMTP 等其他协议,因此,单独抽出了ServletRequest接口,但实际上除了 HTTP 外,并没有其他协议会用 Servlet 处理,所以这是一个过度设计。

HttpServletRequest提供了一系列方法,用于获取 HTTP 请求的各种信息,包括请求头、请求参数、请求体等。

方法 说明
getParameter(String name) 获取请求中的参数,该参数是由 name 指定的
getParameterValues(String name) 返回请求中的参数值,该参数值是由 name 指定的
getRealPath(String path) 获取 Web 资源目录
getAttribute(String name) 返回 name 指定的属性值
getAttributeNames() 返回当前请求的所有属性的名字集合
getCookies() 返回客户端发送的 Cookie
getSession() 获取 session 回话对象
getInputStream() 获取请求主题的输入流
getReader() 获取请求主体的数据流
getMethod() 获取发送请求的方式,如 GET、POST
getParameterNames() 获取请求中所有参数的名称
getRemoteAddr() 获取客户端的 IP 地址
getRemoteHost() 获取客户端名称
getServerPath() 获取请求的文件的路径

此外,HttpServletRequest 还有两个方法:setAttribute()getAttribute(),可以给当前 HttpServletRequest 对象附加属性,相当于将其作为Map<String, Object>使用。

HttpServletResponse

HttpServletResponse 封装了一个 HTTP 响应。由于 HTTP 响应必须先发送 Header,再发送 Body,所以,操作 HttpServletResponse 对象时,必须先调用设置 Header 的方法,最后调用发送 Body 的方法。

方法 说明
getWriter() 获取响应打印流对象
getOutputStream() 获取响应流对象
addCookie(Cookie cookie) 将指定的 Cookie 加入到当前的响应中
addHeader(String name,String value) 将指定的名字和值加入到响应的头信息中
sendError(int sc) 使用指定状态码发送一个错误到客户端
sendRedirect(String location) 发送一个临时的响应到客户端
setDateHeader(String name,long date) 将给出的名字和日期设置响应的头部
setHeader(String name,String value) 将给出的名字和值设置响应的头部
setStatus(int sc) 给当前响应设置状态码
setContentType(String ContentType) 设置响应的 MIME 类型

写入响应时,需要通过getOutputStream()获取写入流或者通过getWriter()获取字符流。Content-Length 由服务器自动计算,不需要手动设置。

Warning

写入完毕后需要调用 flush(),因为大部分 Web 服务器都基于 HTTP/1.1 协议,会复用 TCP 连接。如果没有调用 flush(),将导致缓冲区的内容无法及时发送到客户端。此外,写入完毕后千万不要调用 close(),原因同样是因为会复用 TCP 连接,如果关闭写入流,将关闭 TCP 连接,使得 Web 服务器无法复用此 TCP 连接。

JSP 基础

JSP( JavaServer Pages) 是与 PHPASPASP.NET 等类似的脚本语言,JSP是为了简化Servlet的处理流程而出现的替代品,早期的Java EE因为只能使用Servlet来处理客户端请求而显得非常的繁琐和不便,使用 JSP 可以快速的完成后端逻辑请求。

正因为在JSP中可以直接调用 Java 代码来实现后端逻辑的这一特性,黑客通常会编写带有恶意攻击的 JSP 文件 ( JSP WebShell ) 来实现对服务器资源的恶意请求和控制。

现代的 MVC 框架 ( 如:Spring MVC 5.x) 已经完全抛弃了JSP技术,采用了模板引擎(如:Freemark)或者RESTful的方式来实现与客户端的交互工作。

整个 JSP 的内容实际上是一个 HTML,但是稍有不同: - 包含在<%--和--%>之间的是JSP的注释,它们会被完全忽略; - 包含在<%和%>之间的是Java代码,可以编写任意Java代码; - <%= xxx %>可以快捷输出一个变量的值。

JSP 内置了几个变量:

变量名 类型 作用
pageContext PageContext 当前页面共享数据,还可以获取其他 8 个内置对象
request HttpServletRequest 客户端请求对象,包含了所有客户端请求信息
session HttpSession 请求会话
application ServletContext 全局对象,所有用户间共享数据
response HttpServletResponse 响应对象,主要用于服务器端设置响应信息
page Object 当前 Servlet 对象 ,this
out JspWriter 输出对象,数据输出到页面上
config ServletConfig Servlet 的配置对象
exception Throwable 异常对象

JSP 本质上就是一个 Servlet,只不过无需配置映射路径,Web Server 会根据路径查找对应的 .jsp 文件,如果找到了,就自动编译成 Servlet 再执行。在服务器运行过程中,如果修改了 JSP 的内容,那么服务器会自动重新编译。

JSP 高级功能

  1. <%@ page ... %> 定义网页依赖属性,比如脚本语言、error 页面、缓存需求等等,也可以引入 Java
  2. <%@ include ... %> 包含其他文件(静态包含)
  3. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 引入标签库的定义

因为 HTTP 协议是一个无状态协议,即 Web 应用程序无法区分收到的两个 HTTP 请求是否是同一个浏览器发出的。为了跟踪用户状态,服务器可以向浏览器分配一个唯一 ID,并以Cookie的形式发送到浏览器,浏览器在后续访问时总是附带此Cookie,这样,服务器就可以识别用户身份。

Cookie 是最常用的 Http 会话跟踪机制,且所有Servlet容器都应该支持。Session ID必须被编码为 URL 字符串中的一个路径参数,参数的名字必须是 jsessionid

浏览器和服务端创建会话 ( Session ) 后,服务端将生成一个唯一的会话 ID( sessionid ) 用于标识用户身份,然后会将这个会话 ID 通过Cookie的形式返回给浏览器,浏览器接受到Cookie后会在每次请求后端服务的时候带上服务端设置Cookie值,服务端通过读取浏览器的Cookie信息就可以获取到用于标识用户身份的会话 ID,从而实现会话跟踪和用户身份识别。

因为Cookie中存储了用户身份信息,并且还存储于浏览器端,攻击者可以使用XSS漏洞获取到Cookie信息并盗取用户身份就行一些恶意的操作。

除了使用 Cookie 机制可以实现 Session 外,还可以通过隐藏表单、URL 末尾附加 ID 来追踪 Session。这些机制很少使用,最常用的 Session 机制仍然是 Cookie

在使用多台服务器构成集群时,使用 Session 会遇到一些额外的问题。通常,多台服务器集群使用反向代理作为网站入口:

alt text

这将导致用户在 Server 1 上存储的 Session 数据无法被 Server 2 读取,即从 Server 1 登录后,再次请求时被 Server 2 处理,用户仍处于未登录状态。解决上述问题通常有以下两种方案:

  1. 在所有 Web Server 之间进行 Session 复制,但这样会严重消耗网络带宽,并且,每个 Web Server 的内存均存储所有用户的 Session,内存使用率很低。
  2. 粘滞会话(Sticky Session)机制,即反向代理在转发请求的时候,总是根据 JSESSIONID 的值判断,相同的 JSESSIONID 总是转发到固定的 Web Server,但这需要反向代理的支持。

无论采用何种方案,使用 Session 机制,会使得 Web Server 的集群很难扩展,因此,Session 适用于中小型 Web 应用程序。对于大型 Web 应用程序来说,通常需要避免使用 Session 机制。


最后更新: 2024年8月19日 17:59:19
创建日期: 2024年7月23日 18:59:51

评论