从 url 访问服务器资源讨论 Java Web 中的 Servlet

先简单列一下与服务器的交互过程。#

  • 1 访问URL
  • 2 服务器响应
  • 3 返回处理结果

访问url#

① 浏览器开始解析地址,把地址分为域名和路径(如果有的话),然后连接 DNS 服务器,查询这个域名的 IP 地址。

  • DNS 提供的服务就是将域名转换为其服务器的 ip 地址。

② 获得 DNS 返回的 ip 地址后,浏览器开始按照 HTTP 协议的格式向该 ip 地址(服务器)和路径请求内容。

  • 一:浏览器如何把提交的数据封装成http协议格式
  • 相关内容:TCP HTTP
  • 二:数据在网路中怎么流到服务器
  • 相关内容:DNS 代理、CDN、IP 地址、路由、网络结构

服务器响应#

③服务器收到某个 HTTP 请求后,就会把内容按照 HTTP 协议的格式返回到发送这个请求的客户端。

  • 三:服务器是怎么解析和处理数据的
  • 相关内容:HTTP 各种服务器知识、服务器相关语言知识(Java、Python 等)、数据库(SQL、NOSQL)等
  • 四:处理结束后的结果是怎么封装并通过 HTTP 协议返回的
  • 相关内容:HTTP、 各种 web 服务器知识

返回处理结果#

④浏览器收到服务器返回的内容后,开始渲染并显示出来。

  • 五:浏览器(客户端)得到数据后,又是怎么处理 HTTP 响应的
  • 相关内容:HTTP 浏览器
  • 六:浏览器和 JavaScript 怎么处理响应数据,DOM 如何渲染数据
  • 相关内容:DOM、JavaScript 引擎

⑤浏览器与服务器对话结束

好啦,从第一步开始谈。

访问 URL#

一个完整的 url 是由协议、域名、端口、文件路径四个部分组成的。

比如我输入 http://leay.net:8080/index.html

其中 http 代表协议,leay.net 代表域名,8080 是端口,/index.html 是文件路径。

当我们访问该 url 地址时,会返回服务器中物理文件 index.html 的内容,然后浏览器将内容渲染并展示出我们所看到的网页内容。

这里的 index.html 是静态网页文件,当我们需要采用动态网页开发技术时可以采用 jsp。jsp 是一种建立在 Servlet 上的动态网页开发技术。

例如我们打开一个页面,该页面由 Servlet 处理,返回了各种数据,显示在网页上,即动态网页开发。

Servlet#

Servlet 就是运行在 web 服务器端的 Java 程序,通常用于:

  • 接受数据请求
  • 处理请求
  • 完成响应

我们可以把请求交给一个 Servlet 处理。比如提交一个表单给一个处理表单的 Servlet,Servlet 处理后(往往是与数据库的交互)返回处理结果。

我们也可以直接访问 Servlet。不过创建好的Servlet只有映射成虚拟路径,客户端(浏览器)才能对其进行访问。

映射方式是在 web.xml 下如下配置:

<Servlet>
    <Servlet-name>Servlet名称</Servlet-name>
    <Servlet-class>Servlet完整类名</Servlet-class>
</Servlet>
<Servlet-mapping>
    <Servlet-name>Servlet名称</Servlet-name>
    <url-pattern>Servlet对外访问的虚拟路径</url-pattern>
</Servlet-mapping>

在 web.xml 配置文件中将 url 地址与 Servlet 联系起来。

http://leay.net:8080 将请求导向服务器。如果是类似https://localhost:8080http://127.0.0.1:8080 的地址,意味着导向本地的服务器。

在服务器中有软件程序监听着端口。而 url 剩余的部分,即类似 /index.html 这样的文件路径,是由服务器来处理的。

WEB 服务器根据请求的文件路径在 web.xml 配置文件中查找路径所对应的映射信息,然后来访问Servlet。

不过当我们像上面那样访问 index.html 时,并没有在 web.xml 对该路径进行映射呢。为啥呢?

这时候其实是访问的默认 Servlet(缺省Servlet)。默认 Servlet 用于处理其它 Servlet 都不处理的请求。也就是说,Servlet 服务器在接收到访问请求时,如果在 web.xml 文件中找不到匹配的 <Servlet-mapping> 元素的 url,就会将访问请求交给默认 Servlet 处理。当我们访问服务器上的某个静态 html 文件或者图片时,实际上都是在访问这个默认 Servlet。

①在地址栏输入url后,浏览器会搜索自身的DNS缓存,看自身的缓存中是否有www.xxx.com 对应的条目,而且没有过期,如果有且没有过期则解析到此结束。

②如果浏览器自身的缓存里面没有找到对应的条目,那么浏览器会搜索操作系统自身的DNS缓存,如果找到且没有过期则停止搜索解析到此结束。

③如果在Windows系统的DNS缓存也没有找到,那么尝试读取hosts文件,看看这里面有没有该域名对应的IP地址,如果有则解析成功。

④如果在hosts文件中也没有找到对应的条目,浏览器就会发起一个DNS的系统调用,就会向本地配置的首选DNS服务器发起域名解析请求,运营商的DNS服务器首先查找自身的缓存,找到对应的条目,且没有过期,则解析成功。

⑤域名解析的整个过称就是寻址的过称,解析到对应的IP地址之后,就开始搜寻该物理机上的文件目录

*上面两段参考知乎答案 在浏览器地址栏输入一个URL后回车,背后会进行哪些技术步骤? *

服务器响应#

这一步需要我们自己编写 Servlet 来处理请求。

实现Servlet#

  1. 实现 javax.Servlet.Servlet 接口;
  2. 继承 javax.Servlet.GenericServlet 类;
  3. 继承 javax.Servlet.http.HttpServlet 类;

javax.Servlet.Servlet 接口#

该接口从设计上采用了设计模式中的模板模式,定义了几个接口和抽象类。通过实现该接口来实现 Servlet,需要实现该接口的五个方法。

该接口定义了三个生命周期的方法:

1.init()

2.service()

3.destory()

以及另外两个返回 Servlet 相关信息的方法。

三个生命周期方法将在 Servlet 对象特定的状态下被 WEB 服务器调用。

因为实现该接口必须实现接口定义的所有方法,包括某些不用的方法也得实现。所以就有了使用更为方便的 javax.Servlet.GenericServlet 类。

javax.Servlet.GenericServlet类#

该类采用了缺省适配器模式,是实现了 Servlet 接口所有方法的类,只不过方法体为空。我们通过继承此类实现 Servlet,只需重写需要的方法即可。

此类中只有 service() 属于抽象方法,当我们通过继承此类实现 Servlet 时只需要重写这一个方法即可,其它方法可重写可不重写。

此类除了实现了 Servlet 接口的方法,还定义了一些其它的方法。

javax.Servlet.http.HttpServlet类#

HttpServlet 类是 GenericServlet 类的子类,抽象程度更高。

web 应用与客户端的交互方式有 HTTP 等多种协议,不过大多数 web 应用使用的都是 http 协议。HttpServlet 类专门创建应用于 HTTP 的 Servlet。

在此类中,重写了 service() 方法,通过请求的不同,定义了不同的 doXXX() 方法。

同样,在 HTTP 中,最常用的请求方式是 get 和 post,所以我们通过继承此类编写 Servlet 时,重写 doGet(),doPost() 方法即可。

Servlet 的生命周期#

若 HTTP 请求要访问 Servlet,服务器首先会解析请求,检查内存中是否已经有了该 Servlet 对象,若有则直接使用,若无则创建,并调用 init() 方法实现 Servlet 的初始化工作。

每一次访问该 Servlet,调用一次 service() 方法。HTTP 请求要求访问,服务器为这个请求创建代表 HTTP 请求的 ServletRequest 对象和代表 HTTP 响应的 HttpResponse 对象,将他们作为参数传给 Servlet 的 service() 方法。service() 方法从 ServletRequest 对象中获得客户请求信息,并进行处理,再由 ServletResponse 对象生成响应结果。

Servlet 一旦被创建,会驻留在内存中等待客户端的访问,知道服务器关闭或 web 应用被移出服务器时,Servlet 对象才会被销毁。

返回处理结果#

我们可以通过 Servlet 利用输出流把 Servlet 处理的结果(如返回的数据)直接显示出来,以此动态生成 HTML 页面,但是这样如果需要稍微排下版的话,就不得不自己打印输出很多的 HTML 标签。这样还将静态显示的内容和动态产生内容的代码混合在一起了。

JSP#

jsp 通过在标准的 HTML 页面中插入 Java 代码,其静态部分不需要 Java 程序控制。

jsp 是 Servlet 的一种特殊形式,每个 jsp 就是一个 Servlet 实例,jsp 页面由系统编译成 Servlet,Servlet 再负责响应用户请求。

当用户第一次访问 jsp 页面时,该页面都会被 JspServlet 翻译成一个 Servlet 源文件,然后将源文件编译为 .class 文件。

Servlet 源文件继承了 HttpJspBase 类,HttpJspBase 类是 HttpServlet 类的一个子类。

jsp 页面中将 HTML 和 Java 代码耦合在一起,代码的可读性很差,难以修改和维护。

为了减少 jsp 里的 java 代码,调用 JavaBean 组件来显示数据。

不过这样 jsp 中还是有不少 Java 代码。

于是推出了 JSP EL 来进一步减少 jsp 中的代码。

参考#

参考:Java Web中实现Servlet的方式

Web服务器怎么解析URL

怎么通过URL访问到服务器上的物理文件

在浏览器地址栏输入一个URL后回车,背后会进行哪些技术步骤?

注意#

[update-2019-10-09]

本文仅就 Java Web 讨论,且未提及服务器端 Tomcat、nginx 这类 Web 容器,以及请求如何在容器里传递。

这篇文章提到了:Java Web 启动流程

还有就是前后端分离后前后端的责任分配...