【Java知识体系】JavaWeb技术深入探究,重点关注Servlet原理

本文带你深入理解JavaWeb开发,从C/S与B/S架构对比,到Cookie与Session的工作原理,以及Tomcat核心架构和Servlet核心技术。探索Servlet生命周期、设计模式应用,以及Servlet源码解析。
摘要由CSDN通过智能技术生成

大家好!我是未来村村长,就是那个“请你跟我这样做,我就跟你这样做!”的村长👨‍🌾!

||To Up||

未来村村长正推出一系列【To Up】文章,该系列文章重要是对Java开发知识体系的梳理,关注底层原理和知识重点。”天下苦八股文久矣?吾甚哀,若学而作苦,此门无缘,望去之。“该系列与八股文不同,重点在于对知识体系的构建和原理的探究。

一、javaWeb开发概述

1、C/S与B/S

(1)C/S架构

​ C/S架构中,可恶的业务逻辑集中在客户端,没有严格的服务器,直接与数据库服务器进行交互

(2)B/S架构

​ B/S架构中,业务逻辑和数据操作都集中在服务器端,客户端为浏览器。

2、JavaWeb开发

​ 我们所说的WebApp应用程序就是我们平时通过联网使用的程序,可以简单理解为C/S架构是软件,而B/S架构是网页。网页可分为静态网页和动态网页,静态网页是对所有人展示内容相同的网页,动态网页是具有个性展示的网页。

​ WebApp的构建分为前端和后端,前端主要涉及底层有CSS、JS、HTML等,后端涉及底层为Java类库(包含servlet)。前端负责貌美如花,后端负责增删改查。

3、Cookie与Session

(1)Cookie
① 理解Cookie

​ 当浏览器第一次发送请求到服务端时,服务端会为该浏览器创建一个Cookie,将该Cookie会存放在HTTP头部的字段发送给浏览器端,所以Cookie实际上就是Key/Value键值对。

​ 当浏览器再次访问服务器时,会携带服务器端创建的Cookie,服务器通过Cookie中携带的数据区分不同的用户。

② Cookie限制

​ 限制来源于浏览器对每个域名所持有的Cookie大小和数量的限制。

③ Cookie的安全

​ Cookie和Session都是用来追踪客户端的访问记录,Cookie通过把所有要保存的数据通过HTTP的头部从客户端传递到服务端,又从服务端传回客户端,所有数据都存在客户端的浏览器中。

​ Cookie的数据很容易被访问到,所以不能存放用户隐私和重要的数据。

(2)Session
① 理解Session

​ 浏览器端第一次发送请求到服务器端,服务器创建一个Session,同时创建一个Cookie(name为JSESSIONID,value为Session对象的ID)发送到服务端。

​ 浏览器后续发送请求到服务端时,会携带name为JSESSIONID的Cookie键值对,服务器根据该ID区查询Session对象,Session存在则返回,不存在会重新进行Session和Cookie的创建。

② Session机制

​ Session在服务器中实际上是一个HttpSession对象,第一次触发通过request.getSession方法,并将该对象加载到Manager中的session容器保存,Session过期则被回收,服务器关闭时,Session会被序列化到磁盘中。

4、Tomcat的架构

(1)架构

在这里插入图片描述

​ Tomcat的核心组件有两个,一是Connector,二是Container。多个Connector与一个Container形成一个service服务。

  • Connector【Coyote】:主要任务是负责接收浏览器发过来的TCP连接请求,创建一个Request和Reponse对象分别用于和请求端交换数据,然后会产生一个线程来处理这个请求并把产生的Request和Response对象传给这个请求线程,将这个Request和Response对象交给Container处理

  • Container:由4个子容器组成,Engine、Host、Context、Wrapper

    • Engine:定义基本关联关系,管理子容器Host
    • Host:一个Host在Engine中代表一个虚拟主机,这个虚拟主机的作用就是运行多个应用,其子容器为Context
    • Context:代表Servlet的Context,其具备运行Servlet的基本环境,可以没有Engine,Host,但不能没有Context,其作用是通过Mapper对象或Request来管理Servlet实例的执行
    • Wrapper:一个Wrapper代表一个Servlet,其负责一个Servlet的装载、初始化、执行以及资源回收,该容器是最底层的容器
(2)设计模式思想

​ Tomcat中出现了以下设计模式:

  • 门面设计模式:对数据对象的封装再传递,即创建一个Facade对象封装相关数据【数据交互,HttpRequest-HttpRequestFacade】
  • 观察者设计模式:整个运行期间保持观察,观察到相应事件进行反应【Wrapper对Servlet生命周期的管理】
  • 命令设计模式:封装命令,把发出命令和执行命令的责任分开【Conncetor容器命令Container容器】
  • 责任链设计模式:层层递进进行管理和数据传递【Tomcat中容器分层管理】

二、Servlet架构

1、Servlet基础概念和基础运用

(1)概念
① Servlet

定义:Servlet是sun公司开发动态Web的技术,是在API中提供的接口。

功能:读取客户端(浏览器)发送的数据、处理数据并生成结果、返回结果(HTTP响应)。

实现:狭义上讲,servlet是servlet是java语言实现的一个类,Servlet的应用就是根据这个类进行相应的扩展开发:

  • 编写一个java类,继承HttpServlet类
  • 重写HttpServlet类的doGet方法和doPost方法
  • 配置web.xml文件,或者使用注解对servlet进行配置
② WEB-INF

WEB-INF是Java的WEB应用的安全目录。所谓安全就是客户端无法访问,只有服务端可以访问的目录。如果想在页面中直接访问其中的文件,必须通过web.xml文件对要访问的文件进行相应映射才能访问。

  • classes:存放java编译后的字节码文件
  • lib:用于放置第三方jar包
  • web.xml:webapp的配置文件,描述了请求路径与Servlet类之间的映射关系
(2)编写Webapp
① 一般流程
  • 创建webapp项目,创建lib文件夹,若使用第三方库将该jar复制到lib中

  • 修改环境配置文件:web.xml

  • 创建类继承抽象类HttpServlet,重写doget和dopost方法

  • 在web.xml中注册servlet和其映射路径

  • 更改tomcat中的Deployment,添加当前项目的Artifact(.war)进行访问

② 实现HttpServlet
// 导入必需的 java 库
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

// 扩展 HttpServlet 类
public class HelloWorld extends HttpServlet {
 
  private String message;

  public void init() throws ServletException
  {
      // 执行必需的初始化
      message = "Hello World";
  }

  public void doGet(HttpServletRequest request,
                    HttpServletResponse response)
            throws ServletException, IOException
  {
      // 设置响应内容类型
      response.setContentType("text/html");

      // 实际的逻辑是在这里
      PrintWriter out = response.getWriter();
      out.println("<h1>" + message + "</h1>");
  }
  
  public void destroy()
  {
      //什么也不做
  }
}
③ 在web.xml中完成Servlet的注册
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <servlet>
        <servlet-name>MyServlet</servlet-name>
        <servlet-class>包名.MyServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>MyServlet</servlet-name>
        <url-pattern>/请求路径</url-pattern>
    </servlet-mapping>
    
</web-app>
(3)Servlet的生命周期

Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

  • Servlet 初始化后调用 init () 方法。
  • Servlet 调用 service() 方法来处理客户端的请求。
  • Servlet 销毁前调用 destroy() 方法。
  • 最后,Servlet是由 JVM 的垃圾回收器进行垃圾回收的。
servlet接口
public interface Servlet {
    void init(ServletConfig var1) throws ServletException;
 
    ServletConfig getServletConfig();
 
    void service(ServletRequest request, ServletResponse response) throws ServletException, IOException;
 
    String getServletInfo();
 
    void destroy();
}
① init()
public void init() throws ServletException {
  // 初始化代码...
}

Servlet 创建于用户第一次调用对应于该 Servlet 的URL时,但是您也可以指定 Servlet 在服务器第一次启动时被加载。

当用户调用一个Servlet时,就会创建一个Servlet实例,每一个用户请求都会产生一个新的线程,适当的时候移交给doGet或doPost方法。init()方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期。

② service()
public void service(ServletRequest request, 
                    ServletResponse response) 
      throws ServletException, IOException{
}

service() 方法是执行实际任务的主要方法。Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(浏览器)的请求,并把格式化的响应写回给客户端。

每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求类型(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete 等方法。

service() 方法由容器调用,service方法在适当的时候调用 doGet、doPost、doPut、doDelete 等方法。所以不用对 service() 方法做任何动作,您只需要根据来自客户端的请求类型来重写 doGet() 或 doPost() 即可。

③ doGet()
public void doGet(HttpServletRequest request,
                  HttpServletResponse response)
    throws ServletException, IOException {
    // Servlet 代码
}
④ doPost()
public void doPost(HttpServletRequest request,
                   HttpServletResponse response)
    throws ServletException, IOException {
    // Servlet 代码
}
⑤ destoy()
  public void destroy() {
    // 终止化代码...
  }

destroy() 方法只会被调用一次,在 Servlet 生命周期结束时被调用。destroy() 方法可以让您的 Servlet 关闭数据库连接、停止后台线程、把 Cookie 列表或点击计数器写入到磁盘,并执行其他类似的清理活动。

在调用 destroy() 方法之后,servlet 对象被标记为垃圾回收。

2、Servlet容器

​ 在Tomcat中,Context容器直接管理Servlet在容器中的包装类Wrapper,一个Context容器对应一个Webapp,所以Context容器就是一个servlet容器,而Context中又包含了Weapper容器,该容器用于对Servlet的创建和管理。我们还要知道Context的父类容器是Host容器,Context容器由Host容器进行管理。

​ 容器的启动和servlet实例的创建会经过以下步骤:

  • Tomcat的启动:调用start方法返回一个Tomcat对象,启动Tomcat
  • Webapp的添加:Tomcat调用addWebapp方法(传入url,path参数),返回一个Context
  • Context的初始化:调用ContextConfig的init方法解析相关配置,执行startInternal方法进行容器的初始化
  • Webapp的初始化:解析web.xml文件到Context中,将Servlet包装成Context容器中的StandardWrapper
  • Servlet的实例化:通过Wrapper的loadServlet方法进行Servlet的创建,调用Servlet的init()方法进行初始化

在这里插入图片描述

3、Servlet工作原理

​ 从Servlet的生命周期我们知道init()之后是通过service()方法进行客户端请求的处理,最后进行destory()做一些扫尾工作并等待GC。在Servlet的容器启动时通过ContextConfig实例进行Servlet类的加载,然后生成了StandatdWrapper进行Servlet实例的创建并执行了init()方法进行初始化,接下来将探究Servlet的service()的执行原理。

  • 用户发送请求:http://hostname:port/contextpath/servletpath,向Tomcat发送了一个Request请求
  • Tomcat接收请求:在Tomcat接收并封装为一个Request类的对象之前,通过Mapper来进行url,path与相关容器的映射工作,Mapper会将Request映射到相应的Wrapper对象
  • Servlet接收请求:在Servlet接收请求前,会先执行Filter链和通知web.xml中定义的listener,最后接收到请求执行service()

4、Filter与Listern

​ Filter用于对request,response对象进行修改,Listern用于对事件的监听。

(1)Filter过滤器
① Filter接口

​ 与开发Servlet不同的是,Filter接口并没有相应的实现类可供继承,要开发过滤器,只能直接实现Filer接口。Filter接口中一共有三个方法

public interface Filter {
        //用于完成Filter的初始化
	public void init(FilterConfig filterConfig) throws ServletException;
	//实现过滤功能
        public void doFilter ( ServletRequest request, ServletResponse response, 
FilterChain chain ) throws IOException, ServletException;
        //用于销毁Filter前,完成某些资源的回收
	public void destroy();
}
  • init(FilterConfig filterConfig):Filter初始化,通过filterConfig获取ServletContext对象,并获得<filter>配置下<init-param>的参数值
  • doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ):每个用户的请求进来时,都会调用该方法(在servlet的service方法之前),FilterChain代表整个请求链,doFilter会将请求继续传下去
  • destory:当Filter对象被销毁时调用该方法
② FilterChain

​ Filter类的核心是传递的FilterChain对象,该对象保存了到最终Servlet对象的所有Filter对象,这些对象保存在ApplicationFilterChain对象的filters数组中。

​ FilterChain链上每执行一个Filter对象,数组的当前计数会加1,直到计数大小等于数组长度时,才会执行最终的Servlet。

③ 应用场景

统一POST请求中文字符编码的过滤器、使用Filter实现URL级别的权限认证、实现用户自动登陆、控制浏览器缓存页面中的静态资源的过滤器。

(2)Listern监听器

​ Listener(监听器)是观察者模式的应用,通过方法回调来实现。

① Listern接口

​ 不同功能的Listener需要实现不同的Listener接口,一个Listener也可以实现多个接口。

  • Listern
    • EventListeners:对于事件的监听,其子类接口用于相关属性改变时被触发
      • HttpSessionAttributeListener
      • ServletRequestListener
      • ServletRequestAttributeListener
      • ServletContextAttributeListener
    • LifecycleListeners:在Servlet生命周期的不同状态中触发
      • ServletContextListener
      • HttpSessionListener:创建Session时触发
② 应用场景

​ 监听 Session、request、context 的创建与销毁、监听对象属性变化。

​ 当一个Web应用创建的Session很多时,为了避免Session占用太多的内存,我们可以选择手动将这些内存中的session销毁,那么此时也可以借助监听器技术来实现。

5、url-pattern

​ 在<servlet-mapping>和<filter-mapping>中都有<url-pattern>配置项,作用都是匹配一次请求是否会执行这个Servlet或Filter。

​ Mappper对象会根据请求的URL来匹配每个Serlvet中配置的<url-pattern>,所以当一个Request被创建时,就已经完成了匹配。而Filter的<url-pattern>匹配是在创建ApplicationFilterChain对象时进行的。

三、Servlet源码探究

1、Servlet体系

(1)Servlet规范

​ JavaWeb应用围绕Servlet规范进行运转,而Servlet规范由ServletConfig、ServletRequest、ServletResponse、(ServletContext)构成。

① ServletConfig与ServletContext

​ StandardWrapper和StandardWrapperFacede都实现了ServletConfig接口,StandardWrapperFacede是StandardWrapper的门面类。Servlet初始化时,将StandardWrapperFacede对象传给Servlet对象,用于对数据的封装。

​ ServletContext中也有ApplicationContextFacede对象,进行数据的封装,包装ServletContext只能从容器中拿到它该拿到的数据。

② ServletRequest与ServletResponse

​ 我们通常使用HttpServletRequest和HttpServletResponse。

​ 当Tomcat接收到请求时,会进行org.apache.coyote.Request和org.apache.coyote.Response的创建,作用是通过简单解析将这个请求快速分配给后续线程进行处理。

​ 接下来用户线程会创建org.apache.catalina.connector.Request和org.apache.catalina.connector.Response对象,这两个对象的请求会经过其门面类RequestFacade和ResponseFacade进行封装传递给Servlet容器的ServletRequest和ServletResponse。

(2)Servle体系

2、源码探究

(1)从Servlet到HttpServlet
① Servlet
public interface Servlet {
    void init(ServletConfig var1) throws ServletException;

    ServletConfig getServletConfig();

    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    String getServletInfo();

    void destroy();
}

​ 在Servlet接口中,init()、service()、destroy()与Servlet的生命周期有关。init()需要传入ServletConfig对象作为参数,而该对象来自getServletConfig()方法。getServletInfo()是获取Servlet的相关信息,返回Servlet的一段描述。

​ 我们知道Servlet的规范由ServletConfig、ServletRequest、ServletResponse组成,这体现在其接口方法中,getServletConfig会获取ServletConfig对象,我们来看一下ServletConfig接口。

② ServletConfig
public interface ServletConfig {
    String getServletName();

    ServletContext getServletContext();

    String getInitParameter(String var1);

    Enumeration<String> getInitParameterNames();
}

​ getServletName():获取Servlet在Web.xml中配置的name的值。

​ getInitParameter():获取Servlet的初始化参数

​ getInitParameterNames():获取Servlet的初始化参数名称

​ 其中最关键的是ServletContext getServletContext()方法,该方法获取了ServletContext对象。

​ ServletContext即Servlet上下文,代表整个web应用的对象,这个对象全局唯一,而且工程内部的所有servlet都共享这个对象。所以叫全局应用程序共享对象。

​ 当服务器启动,web应用加载时,会创建一个ServletContext对象,唯一代表该web应用,此后该对象一直存活,直到web应用销毁时,ServletContext对象随之销毁。

​ 这里的ServletContext与之前所说的Context不同,Servlet是用来描述数据传输场景的,这里传输的数据指的是ServletRequest和ServletResponse,而传输场景的描述参数来自ServletConfig。

③ GenericServlet实现类

​ 通过接口的描述,我们已经大致知道了一个Servlet的运行原理,我们现在来看其具体实现,这里截取了关键代码进行讲解。

public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
    private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
    private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.LocalStrings");
    
    private transient ServletConfig config;
	
    //无参构造
    public GenericServlet() {
    }
	//销毁方法
    public void destroy() {
    }
    
    //service进行Request的接收和处理并返回Response
    public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    
    //初始化方法:该方法在StandatdWrapper的initServlet()进行调用
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
    
	//获取Servlet的初始化参数
    public String getInitParameter(String name) {
        ServletConfig sc = this.getServletConfig();//获取ServletConfig
        if (sc == null) {
            throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
        } else {
            return sc.getInitParameter(name);//通过ServletConfig的getInitParameter方法获取Servlst初始化参数
        }
    }
	
    //返回
    public ServletConfig getServletConfig() {
        return this.config;
    }

    public ServletContext getServletContext() {
        ServletConfig sc = this.getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(lStrings.getString("err.servlet_config_not_initialized"));
        } else {
            return sc.getServletContext();
        }
    }

    public void init() throws ServletException {
    }
}
  • init(ServletConfig config):该方法是进行Servlet的初始化,获取了ServletConfig参数。该过程是在StandardWrapper的initServlet()进行执行,该方法调用了Servlet的init方法,并传入包装了StandardWrapper对象的StandardWrapperFacade作为ServletConfig传给Servlet。
  • getInitParameter(String name):该方法通过获取到的ServletConfig对象调用getInitParameter()来获取初始化参数。
  • ServletContext getServletContext():该方法通过获取到的ServletConfig对象调用getServletContext()来获取ServletContext对象进行数据传输场景的建立
④ HtppServlet实现类

​ 通过GenericServlet实现类,我们已经完全知道了Servlet的初始化过程,我们现在通过HttpServlet来探究Request与Response的处理过程。我们这里只关注三个方法:doGet()、doPost()、Service()。

public abstract class HttpServlet extends GenericServlet implements Serializable {
    //相关参数
    private static final String METHOD_DELETE = "DELETE";
    private static final String METHOD_HEAD = "HEAD";
    private static final String METHOD_GET = "GET";
    private static final String METHOD_OPTIONS = "OPTIONS";
    private static final String METHOD_POST = "POST";
    private static final String METHOD_PUT = "PUT";
    private static final String METHOD_TRACE = "TRACE";
    private static final String HEADER_IFMODSINCE = "If-Modified-Since";
    private static final String HEADER_LASTMOD = "Last-Modified";
    private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";
    private static ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");

    public HttpServlet() {
    }
	//doGet方法
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }
	//doPost方法
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_post_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }
    
    //service
    //1、处理相关方法
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince = req.getDateHeader("If-Modified-Since");
                if (ifModifiedSince < lastModified) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }

  	//2、将接收到的ServletRequest和ServletReponse转化为HttpServletxxx
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            //类型转换
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException("non-HTTP request or response");
        }

        this.service(request, response);
    }
}

  • service(ServletRequest req, ServletResponse res):将接收到的ServletRequsest对象转换成了HttpServletRequest类型的对象,把ServletResponse对象转换成了HttpServletResponse类型的对象。

  • service(HttpServletRequest req, HttpServletResponse resp):通过HttpServletRequest.getMethod()获取request的请求类型,根据请求的类型执行相应的方法

  • doGet、doPost等方法:我们要对Request进行读取时并进行业务操作,只需要对doGet和doPost方法进行重写(还有其他方法)即可。

​ 总结:从Servlet和ServletConfig接口,我们了解了Servlet初始化的原理,从GenericServlet实现类我们知道了Servlet的具体实现,从HttpServlet我们知道了Servlet怎么接收Request和Reponse。

​ 之前我们知道Request是Tomcat创建的对象,通过容器传输给Servlet,但是对于ServletRequest、HttpServletRequest的具体实现我们还不知道。

(2)从ServletRequest到HttpServletRequest
① ServletRequest
public interface ServletRequest {
    Object getAttribute(String var1);

    Enumeration<String> getAttributeNames();

    String getCharacterEncoding();

    void setCharacterEncoding(String var1) throws UnsupportedEncodingException;

    int getContentLength();

    String getContentType();

    ServletInputStream getInputStream() throws IOException;

    String getParameter(String var1);//以字符串形式返回请求参数的值,或者如果参数不存在则返回 null。

    Enumeration<String> getParameterNames();

    String[] getParameterValues(String var1);

    Map<String, String[]> getParameterMap();

    String getProtocol();

    String getScheme();

    String getServerName();

    int getServerPort();//返回接收到这个请求的端口号。

    BufferedReader getReader() throws IOException;

    String getRemoteAddr();

    String getRemoteHost();

    void setAttribute(String var1, Object var2);

    void removeAttribute(String var1);

    Locale getLocale();//基于 Accept-Language 头,返回客户端接受内容的首选的区域设置。

    Enumeration<Locale> getLocales();

    boolean isSecure();

    RequestDispatcher getRequestDispatcher(String var1);

    /** @deprecated */
    String getRealPath(String var1);

    int getRemotePort();

    String getLocalName();

    String getLocalAddr();

    int getLocalPort();

    ServletContext getServletContext();

    AsyncContext startAsync() throws IllegalStateException;

    AsyncContext startAsync(ServletRequest var1, ServletResponse var2) throws IllegalStateException;

    boolean isAsyncStarted();

    boolean isAsyncSupported();

    AsyncContext getAsyncContext();

    DispatcherType getDispatcherType();
}

​ 从ServletRequest源码我们可以看到大部分代码都是get方法,也符合Request请求的特征,我们只需要知道Request的相关信息即可。

② HttpServletRequest
public interface HttpServletRequest extends ServletRequest {

    Cookie[] getCookies();//返回一个数组,包含客户端发送该请求的所有的 Cookie 对象。

    long getDateHeader(String var1);

    String getHeader(String var1);//以字符串形式返回指定的请求头的值。

    Enumeration<String> getHeaders(String var1);

    Enumeration<String> getHeaderNames();//返回一个枚举,包含在该请求中包含的所有的头名。
    
    int getIntHeader(String var1);//返回请求头,值为int

    String getMethod();//返回请求方法

    String getPathInfo();//当请求发出时,返回与客户端发送的 URL 相关的任何额外的路径信息。

    String getPathTranslated();

    String getContextPath();

    String getQueryString();

    String getRemoteUser();//如果用户已通过身份验证,则返回发出请求的登录用户,或者如果用户未通过身份验证,则返回 null。

    boolean isUserInRole(String var1);

    Principal getUserPrincipal();

    String getRequestedSessionId();//返回由客户端指定的 session 会话 ID。

    String getRequestURI();//返回该请求的URI

    StringBuffer getRequestURL();//返回该请求的URL

    String getServletPath();//返回调用该Servlet请求的URL

    HttpSession getSession(boolean var1);//返回与该请求关联的当前 HttpSession,或者如果没有当前会话,且创建是真的,则返回一个新的 session 会话。

    HttpSession getSession();//返回与该请求关联的当前 session 会话,或者如果请求没有 session 会话,则创建一个。


}

以下是http常用到的请求头相关信息,我们可以通过HttpServletRequest获取。

头信息描述
Accept这个头信息指定浏览器或其他客户端可以处理的 MIME 类型。值 image/pngimage/jpeg 是最常见的两种可能值。
Accept-Charset这个头信息指定浏览器可以用来显示信息的字符集。例如 ISO-8859-1。
Accept-Encoding这个头信息指定浏览器知道如何处理的编码类型。值 gzipcompress 是最常见的两种可能值。
Accept-Language这个头信息指定客户端的首选语言,在这种情况下,Servlet 会产生多种语言的结果。例如,en、en-us、ru 等。
Authorization这个头信息用于客户端在访问受密码保护的网页时识别自己的身份。
Connection这个头信息指示客户端是否可以处理持久 HTTP 连接。持久连接允许客户端或其他浏览器通过单个请求来检索多个文件。值 Keep-Alive 意味着使用了持续连接。
Content-Length这个头信息只适用于 POST 请求,并给出 POST 数据的大小(以字节为单位)。
Cookie这个头信息把之前发送到浏览器的 cookies 返回到服务器。
Host这个头信息指定原始的 URL 中的主机和端口。
If-Modified-Since这个头信息表示只有当页面在指定的日期后已更改时,客户端想要的页面。如果没有新的结果可以使用,服务器会发送一个 304 代码,表示 Not Modified 头信息。
If-Unmodified-Since这个头信息是 If-Modified-Since 的对立面,它指定只有当文档早于指定日期时,操作才会成功。
Referer这个头信息指示所指向的 Web 页的 URL。例如,如果您在网页 1,点击一个链接到网页 2,当浏览器请求网页 2 时,网页 1 的 URL 就会包含在 Referer 头信息中。
User-Agent这个头信息识别发出请求的浏览器或其他客户端,并可以向不同类型的浏览器返回不同的内容。
(3)从ServletResponse到HttpServletResponse
① ServletResponse
public interface ServletResponse {
    String getCharacterEncoding();

    String getContentType();

    ServletOutputStream getOutputStream() throws IOException;

    PrintWriter getWriter() throws IOException;

    void setCharacterEncoding(String var1);

    void setContentLength(int var1);//设置在 HTTP Servlet 响应中的内容主体的长度,该方法设置 HTTP Content-Length 头。

    void setContentType(String var1);//如果响应还未被提交,设置被发送到客户端的响应的内容类型。

    void setBufferSize(int var1);//为响应主体设置首选的缓冲区大小。

    int getBufferSize();

    void flushBuffer() throws IOException;

    void resetBuffer();

    boolean isCommitted();

    void reset();

    void setLocale(Locale var1);//如果响应还未被提交,设置响应的区域。

    Locale getLocale();
}

从ServletResponse源码我们可以看到大部分代码都是Set方法,也符合Response响应的特征。

② HttpServletResponse
public interface HttpServletResponse extends ServletResponse {
    //状态码
    int SC_CONTINUE = 100;
    int SC_SWITCHING_PROTOCOLS = 101;
    int SC_OK = 200;
    int SC_CREATED = 201;
    int SC_ACCEPTED = 202;
    int SC_NON_AUTHORITATIVE_INFORMATION = 203;
    int SC_NO_CONTENT = 204;
    int SC_RESET_CONTENT = 205;
    int SC_PARTIAL_CONTENT = 206;
    int SC_MULTIPLE_CHOICES = 300;
    int SC_MOVED_PERMANENTLY = 301;
    int SC_MOVED_TEMPORARILY = 302;
    int SC_FOUND = 302;
    int SC_SEE_OTHER = 303;
    int SC_NOT_MODIFIED = 304;
    int SC_USE_PROXY = 305;
    int SC_TEMPORARY_REDIRECT = 307;
    int SC_BAD_REQUEST = 400;
    int SC_UNAUTHORIZED = 401;
    int SC_PAYMENT_REQUIRED = 402;
    int SC_FORBIDDEN = 403;
    int SC_NOT_FOUND = 404;
    int SC_METHOD_NOT_ALLOWED = 405;
    int SC_NOT_ACCEPTABLE = 406;
    int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
    int SC_REQUEST_TIMEOUT = 408;
    int SC_CONFLICT = 409;
    int SC_GONE = 410;
    int SC_LENGTH_REQUIRED = 411;
    int SC_PRECONDITION_FAILED = 412;
    int SC_REQUEST_ENTITY_TOO_LARGE = 413;
    int SC_REQUEST_URI_TOO_LONG = 414;
    int SC_UNSUPPORTED_MEDIA_TYPE = 415;
    int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
    int SC_EXPECTATION_FAILED = 417;
    int SC_INTERNAL_SERVER_ERROR = 500;
    int SC_NOT_IMPLEMENTED = 501;
    int SC_BAD_GATEWAY = 502;
    int SC_SERVICE_UNAVAILABLE = 503;
    int SC_GATEWAY_TIMEOUT = 504;
    int SC_HTTP_VERSION_NOT_SUPPORTED = 505;

    void addCookie(Cookie var1);//把指定的 cookie 添加到响应。

    boolean containsHeader(String var1);

    String encodeURL(String var1);

    String encodeRedirectURL(String var1);

    /** @deprecated */
    String encodeUrl(String var1);

    /** @deprecated */
    String encodeRedirectUrl(String var1);

    void sendError(int var1, String var2) throws IOException;//使用指定的状态码发送错误响应到客户端,并清除缓冲区。

    void sendError(int var1) throws IOException;

    void sendRedirect(String var1) throws IOException;//使用指定的重定向位置 URL 发送临时重定向响应到客户端。

    void setDateHeader(String var1, long var2);

    void addDateHeader(String var1, long var2);

    void setHeader(String var1, String var2);

    void addHeader(String var1, String var2);//添加一个带有给定的名称和值的响应报头。

    void setIntHeader(String var1, int var2);

    void addIntHeader(String var1, int var2);//添加一个带有给定的名称和整数值的响应报头。

    void setStatus(int var1);

    /** @deprecated */
    void setStatus(int var1, String var2);

    int getStatus();

    String getHeader(String var1);

    Collection<String> getHeaders(String var1);

    Collection<String> getHeaderNames();
}

我们可以看到HttpServletReponse在接口中定义了状态码常量,并在ServletResponse基础上添加了部分方法。

响应头相关信息如下:

头信息描述
Allow这个头信息指定服务器支持的请求方法(GET、POST 等)。
Cache-Control这个头信息指定响应文档在何种情况下可以安全地缓存。可能的值有:public、privateno-cache 等。Public 意味着文档是可缓存,Private 意味着文档是单个用户私用文档,且只能存储在私有(非共享)缓存中,no-cache 意味着文档不应被缓存。
Connection这个头信息指示浏览器是否使用持久 HTTP 连接。值 close 指示浏览器不使用持久 HTTP 连接,值 keep-alive 意味着使用持久连接。
Content-Disposition这个头信息可以让您请求浏览器要求用户以给定名称的文件把响应保存到磁盘。
Content-Encoding在传输过程中,这个头信息指定页面的编码方式。
Content-Language这个头信息表示文档编写所使用的语言。例如,en、en-us、ru 等。
Content-Length这个头信息指示响应中的字节数。只有当浏览器使用持久(keep-alive)HTTP 连接时才需要这些信息。
Content-Type这个头信息提供了响应文档的 MIME(Multipurpose Internet Mail Extension)类型。
Expires这个头信息指定内容过期的时间,在这之后内容不再被缓存。
Last-Modified这个头信息指示文档的最后修改时间。然后,客户端可以缓存文件,并在以后的请求中通过 If-Modified-Since 请求头信息提供一个日期。
Location这个头信息应被包含在所有的带有状态码的响应中。在 300s 内,这会通知浏览器文档的地址。浏览器会自动重新连接到这个位置,并获取新的文档。
Refresh这个头信息指定浏览器应该如何尽快请求更新的页面。您可以指定页面刷新的秒数。
Retry-After这个头信息可以与 503(Service Unavailable 服务不可用)响应配合使用,这会告诉客户端多久就可以重复它的请求。
Set-Cookie这个头信息指定一个与页面关联的 cookie。

到此JavaWeb技术解析完结。

——————————————————————

作者:未来村村长

参考:《深入分析JavaWeb技术内幕》——阿里巴巴技术丛书-许令波

个人网站:www.76pl.com

👨‍🌾点个关注,在未来村不会迷路👩‍🌾

——————————————————————

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

未来村村长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值