从 ServletRequest 到 Spring 抽象:Web 请求的底层基石与演化

引言:一切请求的起点

在 Java Web 开发中,无论你使用 Spring MVC、WebSocket 还是纯 Servlet,每个请求的入口都源自一个对象------ServletRequest。这是 Servlet 规范定义的根接口,它封装了客户端请求的最基本信息:参数、属性、输入流、服务器信息等。而我们在之前深入分析的 ServerHttpRequest(Spring 对 HTTP 请求的封装)实际上是对 HttpServletRequestServletRequest 的子接口)的进一步抽象和增强。

今天,我们就以 ServletRequest 为核心,逐行解析其方法,并联系之前讨论的 HttpMessageServerHttpRequest 等接口,揭示从 Servlet 规范到 Spring Web 框架的演化脉络。


一、ServletRequest:定义与设计哲学

java 复制代码
package jakarta.servlet;

public interface ServletRequest {
    // ... 方法
}
  • 包名jakarta.servlet(从 Java EE 迁移到 Jakarta EE,但本质不变)。
  • 设计目的 :提供一个与协议无关的请求信息视图。它不限定于 HTTP,可以用于任何协议(如 FTP、SMTP),但实践中几乎总是通过 HttpServletRequest 子接口用于 HTTP。
  • 实现者 :由 Servlet 容器(如 Tomcat、Jetty)提供具体实现,开发者通过 service(ServletRequest req, ServletResponse res) 方法获得实例。

与 Spring 接口的关系

  • ServletRequest 是 Servlet 规范的"地基"。
  • HttpServletRequest 扩展它,增加 HTTP 协议特定方法(如 getHeadergetMethodgetRequestURI)。
  • Spring 的 ServerHttpRequest 又进一步封装 HttpServletRequest,提供更便利的 API(如 getHeaders() 返回 HttpHeaders 对象)和异步控制。

二、核心方法分类解析

2.1 属性管理:请求范围内的数据容器

ServletRequest 提供了类似 Map 的属性存储,生命周期与请求一致。

java 复制代码
Object getAttribute(String name);
Enumeration<String> getAttributeNames();
void setAttribute(String name, Object o);
void removeAttribute(String name);
  • 作用:在请求处理链中传递数据(例如,在过滤器中设置属性,在 Servlet 中读取)。也用于容器注入特定信息(如 HTTPS 客户端证书)。
  • HttpRequest.getAttributes() 对应 :Spring 的 HttpRequest 也提供了 getAttributes(),但 Spring 的 attributes 是 Map<String, Object>,而 Servlet 的 attributes 是 Enumeration 风格的旧式 API。Spring 对此进行了现代化封装。

2.2 字符编码与内容长度

java 复制代码
String getCharacterEncoding();
void setCharacterEncoding(String encoding) throws UnsupportedEncodingException;
default void setCharacterEncoding(Charset encoding);
int getContentLength();
long getContentLengthLong();
String getContentType();
  • 作用
    • getCharacterEncoding:获取请求体的字符编码(如 UTF-8)。若未设置,返回 null。
    • setCharacterEncoding:必须在读取请求体(getReader()getInputStream())之前调用,才能生效。用于覆盖默认编码。
    • getContentLength / getContentLengthLong:获取 Content-Length 头值,-1 表示未知。
    • getContentType:获取 Content-Type 头值(如 application/json)。
  • 在 Spring 中HttpHeaders 提供了 getContentType()getContentLength() 等方法,更直接、类型安全。

2.3 输入流:读取请求体

java 复制代码
ServletInputStream getInputStream() throws IOException;
BufferedReader getReader() throws IOException;
  • getInputStream:以二进制流方式读取请求体(用于文件上传、图片等)。
  • getReader :以字符流方式读取请求体(用于文本数据,如 JSON、表单)。它会根据 getCharacterEncoding() 指定的编码自动解码。
  • 重要限制 :两者只能调用其一,否则抛出 IllegalStateException
  • 在 Spring 中HttpInputMessage.getBody() 返回 InputStream,而 ServerHttpRequest 同时继承 HttpInputMessage,因此也能通过 getBody() 获取原始字节流。

2.4 参数解析:查询字符串与表单数据

java 复制代码
String getParameter(String name);
Enumeration<String> getParameterNames();
String[] getParameterValues(String name);
Map<String,String[]> getParameterMap();
  • 作用:获取 HTTP 请求参数(Query String 或 POST 表单数据)。
  • 注意
    • 对于 application/x-www-form-urlencodedmultipart/form-data,容器会自动解析。
    • getParameter 只返回第一个值,getParameterValues 返回所有值。
    • 调用这些方法会触发参数解析,可能消耗输入流,因此调用 getInputStreamgetReader 后调用这些方法可能无效或抛出异常。
  • Spring 的等价物 :Spring MVC 通过 @RequestParam 注解直接绑定参数,底层也是调用这些方法。

2.5 服务器信息:协议、主机、端口、远程地址

java 复制代码
String getProtocol();          // "HTTP/1.1"
String getScheme();            // "http" 或 "https"
String getServerName();        // "example.com"
int getServerPort();           // 80
String getRemoteAddr();        // 客户端 IP
String getRemoteHost();        // 客户端主机名
int getRemotePort();           // 客户端端口
String getLocalName();         // 本地主机名
String getLocalAddr();         // 本地 IP
int getLocalPort();            // 本地端口
  • 作用:获取请求到达的服务器端信息以及客户端的网络地址。
  • 联系之前 :这些信息在 Spring 的 ServerHttpRequest 中通过 getLocalAddress()getRemoteAddress() 返回 InetSocketAddress 对象,比 Servlet 的分散方法更聚合。

2.6 国际化:Locale

java 复制代码
Locale getLocale();
Enumeration<Locale> getLocales();
  • 基于 Accept-Language 头返回客户端的首选语言区域,用于国际化响应内容。

2.7 安全与分发

java 复制代码
boolean isSecure();                         // 是否使用 HTTPS
RequestDispatcher getRequestDispatcher(String path);
ServletContext getServletContext();
  • isSecure:判断请求是否通过安全通道(如 HTTPS)。
  • getRequestDispatcher :获取一个 RequestDispatcher,用于转发(forward)或包含(include)其他资源(如 JSP)。
  • getServletContext:获取 Web 应用的上下文对象,可访问全局配置和资源。

2.8 异步处理支持(Servlet 3.0+)

java 复制代码
AsyncContext startAsync() throws IllegalStateException;
AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
        throws IllegalStateException;
boolean isAsyncStarted();
boolean isAsyncSupported();
AsyncContext getAsyncContext();
DispatcherType getDispatcherType();
  • 作用 :开启异步模式,释放当前线程,由另一个线程处理耗时操作,完成后通过 AsyncContext 完成响应。
  • ServerHttpAsyncRequestControl 的关系 :Spring 的 ServerHttpAsyncRequestControl 是对这些底层方法的封装,提供更友好的 start()complete() 方法。

2.9 新特性(Servlet 6.0)

java 复制代码
String getRequestId();
String getProtocolRequestId();
ServletConnection getServletConnection();
  • getRequestId:容器生成的唯一请求标识(用于追踪)。
  • getProtocolRequestId:协议层提供的标识(如 HTTP/2 的 stream ID)。
  • getServletConnection:获取底层网络连接详情,提供更细粒度的网络信息。

三、ServletRequest 与 Spring 接口的对比

我们将 ServletRequest 的主要功能与 Spring 的 HttpRequest/ServerHttpRequest 对照:

功能 Servlet API Spring 抽象
获取请求头 HttpServletRequest.getHeader() HttpHeaders 对象,通过 getHeaders() 获取
获取请求方法 HttpServletRequest.getMethod() HttpMethod 枚举,通过 getMethod() 获取
获取 URI HttpServletRequest.getRequestURI() URI 对象,通过 getURI() 获取
获取参数 getParameter() 通过 @RequestParam 或手动解析
获取输入流 getInputStream() / getReader() getBody() 返回 InputStream
异步控制 startAsync() / AsyncContext ServerHttpAsyncRequestControl
客户端地址 getRemoteAddr() + getRemotePort() getRemoteAddress() 返回 InetSocketAddress

Spring 的设计更加面向对象类型安全 ,而 Servlet API 更加面向字符串低层


四、在 IM 软件中的实际角色

在你的 IM 后端,ServletRequest(确切地说是 HttpServletRequest)是整个请求处理链的源头

  1. WebSocket 握手 :握手请求首先到达 Servlet 容器,被包装为 HttpServletRequest,然后 Spring 的 HandshakeInterceptor 通过 ServerHttpRequest 访问其中的头、URI、远程地址等信息。
  2. REST API :如用户注册、登录、获取历史记录等普通 HTTP 接口,都依赖 HttpServletRequest 获取参数、请求体和认证头。
  3. 异步处理:若某些接口需要长时间处理(如等待消息队列),可使用异步 Servlet 释放线程,提升并发能力。

因此,尽管你在 Spring 层主要与 ServerHttpRequest 打交道,但理解 ServletRequest 能帮你更好地调试和优化底层行为。


五、总结:从基石到高楼

ServletRequest 是 Servlet 规范的基石,它定义了请求对象最基本的契约。Spring 在它之上构建了更高级的抽象,但底层最终都委托给容器提供的 ServletRequest 实现。

通过对比 ServletRequestServerHttpRequest,我们可以清晰地看到 Java Web 技术的演进路径:

  • 低层:面向字符串、枚举、输入流,与容器紧密耦合。
  • 高层:面向对象、类型安全、更符合现代编程习惯。

在你的 IM 开发中,大部分时间你都将工作在 Spring 的高层抽象上,但当遇到性能瓶颈、需要直接操作底层容器时,对 ServletRequest 的理解会成为你的得力工具。


附录:ServletRequest 完整代码及逐行注释(节选)

java 复制代码
/**
 * 定义了一个向 Servlet 提供客户端请求信息的对象。
 * Servlet 容器创建该对象并将其作为参数传递给 Servlet 的 service 方法。
 * <p>
 * 该对象提供参数名和值、属性、输入流等数据。
 * 扩展该接口的接口可以提供协议特定的数据(如 {@link HttpServletRequest} 提供 HTTP 数据)。
 */
public interface ServletRequest {

    /**
     * 返回指定名称的属性值,若不存在则返回 null。
     * 属性可由容器设置(如 HTTPS 客户端证书),也可由程序通过 setAttribute 设置。
     * 属性名应以包名规范命名,以 jakarta.* 开头的保留给平台使用。
     */
    Object getAttribute(String name);

    /**
     * 返回所有属性名的枚举。
     */
    Enumeration<String> getAttributeNames();

    /**
     * 获取请求体使用的字符编码,若未指定则返回 null。
     * 优先级:每请求设置 > Web应用默认 > 容器默认。
     */
    String getCharacterEncoding();

    /**
     * 覆盖请求体字符编码,必须在读取请求体之前调用。
     */
    void setCharacterEncoding(String encoding) throws UnsupportedEncodingException;

    /**
     * 获取请求体长度(字节),-1 表示未知或大于 Integer.MAX_VALUE。
     */
    int getContentLength();

    /**
     * 获取请求体长度(长整型),-1 表示未知。
     */
    long getContentLengthLong();

    /**
     * 获取请求体的 MIME 类型。
     */
    String getContentType();

    /**
     * 以二进制流方式获取请求体。
     * 与 getReader() 互斥。
     */
    ServletInputStream getInputStream() throws IOException;

    /**
     * 获取参数值(单个),若参数不存在返回 null。
     * 若参数有多个值,返回第一个。
     * 调用该方法可能触发参数解析,需注意与输入流的关系。
     */
    String getParameter(String name);

    /**
     * 返回所有参数名的枚举。
     */
    Enumeration<String> getParameterNames();

    /**
     * 返回参数的所有值数组,若不存在返回 null。
     */
    String[] getParameterValues(String name);

    /**
     * 返回参数的 Map,键为 String,值为 String[]。
     */
    Map<String,String[]> getParameterMap();

    /**
     * 获取协议名称和版本,如 "HTTP/1.1"。
     */
    String getProtocol();

    /**
     * 获取请求使用的协议方案(如 http, https)。
     */
    String getScheme();

    /**
     * 获取服务器主机名。
     */
    String getServerName();

    /**
     * 获取服务器端口。
     */
    int getServerPort();

    /**
     * 以字符流方式获取请求体,自动按编码解码。
     * 与 getInputStream() 互斥。
     */
    BufferedReader getReader() throws IOException;

    /**
     * 获取客户端 IP 地址。
     */
    String getRemoteAddr();

    /**
     * 获取客户端完全限定域名,若无法解析则返回 IP 地址。
     */
    String getRemoteHost();

    /**
     * 设置请求属性。
     */
    void setAttribute(String name, Object o);

    /**
     * 移除请求属性。
     */
    void removeAttribute(String name);

    /**
     * 获取客户端首选语言区域。
     */
    Locale getLocale();

    /**
     * 获取客户端可接受的语言区域列表(按优先级降序)。
     */
    Enumeration<Locale> getLocales();

    /**
     * 判断请求是否通过安全通道(如 HTTPS)。
     */
    boolean isSecure();

    /**
     * 获取 RequestDispatcher,用于转发或包含资源。
     */
    RequestDispatcher getRequestDispatcher(String path);

    /**
     * 获取客户端端口。
     */
    int getRemotePort();

    /**
     * 获取接收请求的本地主机名。
     */
    String getLocalName();

    /**
     * 获取接收请求的本地 IP 地址。
     */
    String getLocalAddr();

    /**
     * 获取接收请求的本地端口。
     */
    int getLocalPort();

    /**
     * 获取 ServletContext。
     */
    ServletContext getServletContext();

    /**
     * 启动异步处理(使用当前请求和响应)。
     */
    AsyncContext startAsync() throws IllegalStateException;

    /**
     * 启动异步处理(指定请求和响应)。
     */
    AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
            throws IllegalStateException;

    /**
     * 判断是否已启动异步模式。
     */
    boolean isAsyncStarted();

    /**
     * 判断是否支持异步处理。
     */
    boolean isAsyncSupported();

    /**
     * 获取当前的 AsyncContext。
     */
    AsyncContext getAsyncContext();

    /**
     * 获取当前请求的分发类型(如 FORWARD, INCLUDE, REQUEST, ASYNC)。
     */
    DispatcherType getDispatcherType();

    /**
     * 获取容器生成的唯一请求标识。
     */
    String getRequestId();

    /**
     * 获取协议层提供的请求标识(如 HTTP/2 stream ID)。
     */
    String getProtocolRequestId();

    /**
     * 获取网络连接详情。
     */
    ServletConnection getServletConnection();
}

这份源码注释不仅解释了每个方法的字面含义,还联系了 Spring 的高层抽象和你在 IM 开发中的实际场景,希望能帮助你建立从底层规范到应用框架的完整认知。

从协议无关到 HTTP 专用:HttpServletRequest 在 Web 请求处理中的核心地位

在之前的讨论中,我们已经走过了从 SocketAddress(物理地址)、URI(逻辑资源)、HttpMessage(消息头)到 ServletRequest(协议无关请求)的完整路径。今天,我们聚焦于 HttpServletRequest------它是 Servlet 规范中专门针对 HTTP 协议的请求接口,是几乎所有 Java Web 应用(包括IM 软件)与容器交互的直接入口。

HttpServletRequest 不仅继承了 ServletRequest 的所有基础能力(参数、属性、输入流),更增加了 HTTP 协议特有的功能:头处理、Cookie、会话管理、认证授权、文件上传、协议升级 等。而 Spring 的 ServerHttpRequest 则是在此基础上的进一步抽象,提供更现代、类型安全的 API。理解这三者的关系,就等于打通了从容器底层框架高层的任督二脉。


一、HttpServletRequest:HTTP 协议的"专属代言人"

1.1 继承与定位

java 复制代码
public interface HttpServletRequest extends ServletRequest {
    // ... 大量 HTTP 特定方法
}
  • 继承自 ServletRequest :因此拥有所有基础方法(getAttributegetParametergetInputStream 等)。
  • 专为 HTTP 设计:所有方法都围绕 HTTP 协议的方方面面------请求行、请求头、请求体、会话、认证等。
  • 由容器实现 :Tomcat、Jetty 等容器在接收到 HTTP 请求时,会创建该接口的实例,并传递给 Servlet 的 service 方法(或 Spring 的 DispatcherServlet)。

1.2 认证与安全相关方法

java 复制代码
String getAuthType();                    // 返回认证类型:BASIC, FORM, CLIENT_CERT, DIGEST
String getRemoteUser();                  // 返回已认证的用户名
boolean isUserInRole(String role);       // 判断用户是否属于某个角色
java.security.Principal getUserPrincipal(); // 返回 Principal 对象
boolean authenticate(HttpServletResponse response) throws IOException, ServletException;
void login(String username, String password) throws ServletException;
void logout() throws ServletException;
  • getUserPrincipal() :这正是我们之前讨论过的 java.security.Principal!它代表当前认证用户。在 Spring Security 中,它会被包装成 Authentication 对象。
  • login / logout:允许在代码中手动执行登录/登出(Servlet 3.0 新增),通常与表单认证配合使用。
  • authenticate:触发容器配置的认证机制(如 BASIC 弹窗),若未认证则返回 401。

在 IM 中的角色 :虽然你的项目使用 JWT 无状态认证,但如果你需要支持传统的 Session-based 登录,这些方法就派上用场了。而 getUserPrincipal() 可以作为获取当前用户的统一方式,与 Spring Security 集成后,principal 参数就是从这里来的。

1.3 请求头相关方法

java 复制代码
String getHeader(String name);
Enumeration<String> getHeaders(String name);
Enumeration<String> getHeaderNames();
long getDateHeader(String name);
int getIntHeader(String name);
  • getHeader:获取第一个值(最常用)。
  • getHeaders:获取所有值(因为有些头可以出现多次)。
  • getDateHeader :自动解析日期格式头(如 If-Modified-Since)为毫秒数。
  • getIntHeader :解析整数值头(如 Content-Length)。

与 Spring HttpHeaders 的联系 :Spring 的 HttpHeaders 类提供了更友好的类型安全方法(getFirstgetContentType() 等),并且封装了这些底层调用。

1.4 URL 与路径信息

java 复制代码
String getMethod();                      // GET, POST, etc.
String getRequestURI();                  // /context/servlet/path
StringBuffer getRequestURL();            // http://host:port/context/servlet/path
String getContextPath();                 // /myapp
String getServletPath();                 // /servlet
String getPathInfo();                    // 额外路径信息(如 /extra)
String getPathTranslated();              // 路径对应的真实文件系统路径
String getQueryString();                 // a=b&c=d
  • getMethod :最常用的方法之一,用于判断请求类型。在 WebSocket 握手中,我们正是通过它检查是否为 GET
  • 路径分解:容器会将 URL 分解为 contextPath、servletPath、pathInfo,以便精确路由。
  • getRequestURL:用于构造重定向 URL 或生成绝对链接。

与 Spring ServerHttpRequest 的关系 :Spring 通过 getURI() 返回一个 java.net.URI 对象,包含了所有这些信息,但以更现代的方式呈现。

java 复制代码
Cookie[] getCookies();
String getRequestedSessionId();
boolean isRequestedSessionIdValid();
boolean isRequestedSessionIdFromCookie();
boolean isRequestedSessionIdFromURL();
HttpSession getSession(boolean create);
HttpSession getSession();
String changeSessionId();
  • Cookie:获取客户端发送的 Cookie 数组。
  • 会话管理getSession() 用于获取或创建 HttpSession,它是服务器端保存用户状态的主要机制(在无状态 JWT 时代使用较少,但在传统 Web 应用中仍广泛使用)。
  • 会话 ID 追踪:检查会话 ID 来源(Cookie 或 URL),判断是否有效。

在 IM 中的角色 :虽然你的 IM 可能主要使用 JWT,但 Spring Security 的默认会话管理仍基于 HttpSession,理解这些方法有助于调试。

1.6 文件上传与 Multipart 支持(Servlet 3.0+)

java 复制代码
Collection<Part> getParts() throws IOException, ServletException;
Part getPart(String name) throws IOException, ServletException;
  • getParts() :获取所有上传的文件部分(Part 对象)。
  • getPart(name):按名称获取特定部分。
  • 前提:请求的 Content-Typemultipart/form-data,且 Servlet 配置了 @MultipartConfig

在 IM 中的潜在应用:头像上传、文件传输等场景会用到。

1.7 协议升级与 HTTP/2 支持

java 复制代码
<T extends HttpUpgradeHandler> T upgrade(Class<T> httpUpgradeHandlerClass) throws IOException, ServletException;
default PushBuilder newPushBuilder() { return null; } // @Deprecated
default Map<String,String> getTrailerFields() { return Collections.emptyMap(); }
default boolean isTrailerFieldsReady() { return true; }
default HttpServletMapping getHttpServletMapping() { ... }
  • upgrade (Servlet 3.1+):这是 WebSocket 握手的关键方法 !当容器检测到 Upgrade: websocket 头时,可以调用此方法将当前 HTTP 连接升级为 WebSocket 协议,并传入自定义的 HttpUpgradeHandler 实现。
  • getTrailerFields(HTTP/2):获取尾部字段(Trailer),用于分块传输编码后的附加头。
  • newPushBuilder(Servlet 4.0,已弃用):用于 HTTP/2 服务器推送,现推荐使用 103 Early Hints。

在 IM 中的核心角色 :对于 WebSocket,upgrade 方法是容器级支持的基础。不过,Spring WebSocket 封装了底层细节,你通常不需要直接调用它。


二、与 ServletRequest 的区别和联系

维度 ServletRequest HttpServletRequest
协议范围 与协议无关(可代表 FTP、SMTP 等) 专门针对 HTTP/HTTPS
核心方法 参数、属性、输入流、服务器信息 增加:头、Cookie、会话、认证、路径分解、上传、升级
主要用途 作为所有请求的根接口 作为 Web 应用的 HTTP 请求标准接口
实现者 容器提供(如 Request 基类) 容器提供(如 Request 的 HTTP 子类)

联系HttpServletRequest 继承ServletRequest,因此它拥有父接口的所有方法,并在此基础上扩展。你的代码中若只依赖 ServletRequest,则可适用于任何协议;若使用 HttpServletRequest,则仅限于 HTTP。


三、与 ServerHttpRequest 的区别和联系

ServerHttpRequest 是 Spring 框架中定义的服务端 HTTP 请求抽象,它并不直接继承 HttpServletRequest,而是封装它。

维度 HttpServletRequest(Servlet API) ServerHttpRequest(Spring)
所属规范 Jakarta Servlet(Java EE / Jakarta EE) Spring Framework
底层实现 由容器(Tomcat/Jetty)直接实现 通常是 Spring 的包装类,内部持有 HttpServletRequest
主要方法 众多基于字符串和枚举的方法(如 getHeader(String) 更面向对象:getHeaders() 返回 HttpHeadersgetMethod() 返回 HttpMethod 枚举,getURI() 返回 URI
异步支持 startAsync() 返回 AsyncContext getAsyncRequestControl() 返回 ServerHttpAsyncRequestControl(更易用)
网络地址 getRemoteAddr()getRemotePort() 分开 getRemoteAddress() 返回统一的 InetSocketAddress
用户身份 getUserPrincipal() 返回 Principal 同样有 getPrincipal() 方法,但通常 Spring Security 会包装

联系

  • Spring 的 ServerHttpRequest 通常通过适配器模式封装 HttpServletRequest
  • HandshakeInterceptor 中,你收到的是 ServerHttpRequest,但内部可以通过 getNativeRequest() 获取底层的 HttpServletRequest 对象(若需调用 Servlet 特有方法)。
  • Spring 提供更现代、类型安全的 API,避免直接操作字符串和枚举。

四、HttpServletRequest 在你的 IM 中的实际应用

尽管你主要工作在 Spring 层,但理解 HttpServletRequest 有助于:

  1. 调试:当遇到容器相关问题时,查看原始请求头和方法。
  2. 性能调优 :例如,通过 getContentLengthLong() 了解请求体大小,提前拒绝过大请求。
  3. WebSocket 握手 :虽然 Spring 隐藏了 upgrade,但原理上握手正是通过调用 upgrade 方法完成的。
  4. 混合架构 :若你还需要提供 REST API,使用 HttpServletRequest 获取原始参数和请求体。
  5. 安全getRemoteAddr()getRemoteHost() 用于 IP 黑白名单,isSecure() 用于强制 HTTPS。

五、总结:从 ServletRequestServerHttpRequest 的进化

  • ServletRequest基础,提供与协议无关的请求模型。
  • HttpServletRequest专用化,增加 HTTP 协议特性,是 Servlet 规范的核心。
  • ServerHttpRequest现代化封装,提供更友好、类型安全的 API,同时保留对底层的访问能力。

在你的 IM 开发中,三者形成了清晰的层次:

  • 底层 :容器提供 HttpServletRequest
  • 中间层 :Spring 将其包装为 ServerHttpRequest,并注入 HandshakeInterceptor
  • 上层 :你的业务代码通过 PrincipalHttpHeaders 等高级抽象操作请求。

理解这层关系,你就能在需要时灵活地在不同层次间切换,写出更健壮、更高效的代码。


附录:HttpServletRequest 核心方法详解(按功能分组)

认证与用户身份

  • getAuthType() → 返回认证机制。
  • getRemoteUser() → 返回已认证用户名。
  • isUserInRole(String) → 角色检查。
  • getUserPrincipal() → 返回 Principal 对象。
  • login(String, String) / logout() → 程序化登录/登出。
  • authenticate(HttpServletResponse) → 触发容器认证。

请求头

  • getHeader(String) → 获取首值。
  • getHeaders(String) → 获取所有值。
  • getHeaderNames() → 获取所有头名。
  • getDateHeader(String) → 解析日期头。
  • getIntHeader(String) → 解析整型头。

请求方法与 URL

  • getMethod() → HTTP 方法。
  • getRequestURI() → 原始路径(不含主机和查询)。
  • getRequestURL() → 完整 URL(不含查询)。
  • getContextPath() → 应用上下文路径。
  • getServletPath() → Servlet 匹配路径。
  • getPathInfo() → 额外路径信息。
  • getPathTranslated() → 真实文件路径。
  • getQueryString() → 查询字符串。

会话

  • getSession(boolean) → 获取/创建会话。
  • getSession() → 默认创建。
  • getRequestedSessionId() → 客户端提供的会话 ID。
  • isRequestedSessionIdValid() → 是否有效。
  • isRequestedSessionIdFromCookie() / fromURL() → 来源。
  • changeSessionId() → 更换会话 ID。

文件上传

  • getParts() → 获取所有上传部件。
  • getPart(String) → 获取指定部件。

协议升级与高级特性

  • upgrade(Class) → 升级到 WebSocket 等。
  • newPushBuilder() → HTTP/2 推送(已弃用)。
  • getTrailerFields() → 尾部字段。
  • isTrailerFieldsReady() → 尾部是否就绪。
  • getHttpServletMapping() → 获取映射信息。

通过这篇分析,你将 HttpServletRequest 放在整个 Servlet 和 Spring 生态的上下文之中,能更清晰地理解每个方法的设计初衷和实际用途。

相关推荐
程序员黑豆1 小时前
鸿蒙应用开发之状态变化通知:@Watch 装饰器详解与实战
前端·harmonyos
swipe1 小时前
13|(前端转全栈)支付成功不等于结束:回调、幂等、超时关单和状态竞争
前端·后端·面试
唐青枫1 小时前
Java Reactor Netty 实战详解:从响应式 HTTP 到 TCP 长连接
java·netty
swipe1 小时前
12|(前端转全栈)点击提交订单后,后端如何用事务守住价格、库存和订单?
前端·后端·面试
小林ixn1 小时前
React + TypeScript 实战:从“类型体操”到“数据持久化”,一次讲透组件通信与副作用管理
前端·react.js·typescript
何时梦醒1 小时前
React + TypeScript 企业级开发实战:从零搭建到组件架构演进
前端·react.js·全栈
Coffeeee1 小时前
AGP9.0的主要变更项,给Gradle来一次大变样
android·前端·gradle
无人生还2 小时前
从 Vue3 到 React · 快速上手系列第 7 篇:副作用与生命周期 —— watch/watchEffect 如何翻译为 useEffect
前端·vue.js·react.js
数聚天成DeepSData2 小时前
外贸海关进出口数据去哪免费下载?从统计到明细的查找指南
linux·服务器·开发语言·前端·网络·人工智能·自然语言处理