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

  • 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://hqweay.cn:8080/index.html。

其中 http 代表协议,hqweay.cn 代表域名,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://hqweay.cn: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 启动流程

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